<!DOCTYPE html>


  <html class="dark page-post">


<head><meta name="generator" content="Hexo 3.9.0">
  <meta charset="utf-8">
  
  <title>ES2015/ES2016/ES2017/ES2018/ES2019 | Poetry&#39;s Blog</title>

  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  
    <meta name="keywords" content="JavaScript,ES6,">
  

  <meta name="description" content="一、前言 ES6是ECMA为JavaScript制定的第6个标准版本 标准委员会最终决定，标准在每年6月正式发布并作为当年的正式版本，接下来的时间里就在此版本的基础上进行改动，直到下一年6月草案就自然变成新一年的版本，这样一来就无需以前的版本号，只要用年份标记即可。ECMAscript 2015是在2015年6月发布ES6的第一个版本。以此类推，ECMAscript 2016是ES6的第二个版本">
<meta name="keywords" content="JavaScript,ES6">
<meta property="og:type" content="article">
<meta property="og:title" content="ES2015&#x2F;ES2016&#x2F;ES2017&#x2F;ES2018&#x2F;ES2019">
<meta property="og:url" content="http://blog.poetries.top/2019/11/17/es6-review-summary/index.html">
<meta property="og:site_name" content="Poetry&#39;s Blog">
<meta property="og:description" content="一、前言 ES6是ECMA为JavaScript制定的第6个标准版本 标准委员会最终决定，标准在每年6月正式发布并作为当年的正式版本，接下来的时间里就在此版本的基础上进行改动，直到下一年6月草案就自然变成新一年的版本，这样一来就无需以前的版本号，只要用年份标记即可。ECMAscript 2015是在2015年6月发布ES6的第一个版本。以此类推，ECMAscript 2016是ES6的第二个版本">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/11/123.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/11/124.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/11/125.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/11/126.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/11/127.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/11/128.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/11/129.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/11/130.png">
<meta property="og:updated_time" content="2020-08-15T04:25:31.906Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="ES2015&#x2F;ES2016&#x2F;ES2017&#x2F;ES2018&#x2F;ES2019">
<meta name="twitter:description" content="一、前言 ES6是ECMA为JavaScript制定的第6个标准版本 标准委员会最终决定，标准在每年6月正式发布并作为当年的正式版本，接下来的时间里就在此版本的基础上进行改动，直到下一年6月草案就自然变成新一年的版本，这样一来就无需以前的版本号，只要用年份标记即可。ECMAscript 2015是在2015年6月发布ES6的第一个版本。以此类推，ECMAscript 2016是ES6的第二个版本">
<meta name="twitter:image" content="https://poetries1.gitee.io/img-repo/2019/11/123.png">

  

  
    <link rel="icon" href="/favicon.ico">
  

  <link href="/css/styles.css?v=c114cbeddx" rel="stylesheet">
<link href="/css/other.css?v=c114cbeddx" rel="stylesheet">


  
    <link rel="stylesheet" href="/css/personal-style.css">
  

  

  
  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "//hm.baidu.com/hm.js?40b1f89aa80f2527b3db779c6898c879";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>


  
  <script type="text/javascript">
	(function(){
	    var bp = document.createElement('script');
	    var curProtocol = window.location.protocol.split(':')[0];
	    if (curProtocol === 'https') {
	        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';        
	    }
	    else {
	        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
	    }
	    var s = document.getElementsByTagName("script")[0];
	    s.parentNode.insertBefore(bp, s);
	})();
  </script>



  
    <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <link rel="stylesheet" href="//cdn.bootcss.com/font-awesome/4.3.0/css/font-awesome.min.css">
  

  <!-- 聊天系统 -->
  
    
   <link type="text/css" rel="stylesheet" href="/renxi/default.css">
   <style>
      #modal {
        position: static !important;
      }
      .filter {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        background: #fe5757;
        animation: colorChange 30s ease-in-out infinite;
        animation-fill-mode: both;
        mix-blend-mode: overlay;
      }
  
      @keyframes colorChange {
        0%, 100% {
            opacity: 0;
        }
        50% {
            opacity: .9;
        }
      }
   </style>
</head>
</html>
<body>
  
  
    <span id="toolbox-mobile" class="toolbox-mobile">导航</span>
  

  <div class="post-header CENTER">
   
  <div class="toolbox">
    <a class="toolbox-entry" href="/">
      <span class="toolbox-entry-text">导航</span>
      <i class="icon-angle-down"></i>
      <i class="icon-home"></i>
    </a>
    <ul class="list-toolbox">
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/archives/"
            rel="noopener noreferrer"
            target="_self"
            >
            博客
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/categories/"
            rel="noopener noreferrer"
            target="_self"
            >
            分类
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/tags/"
            rel="noopener noreferrer"
            target="_self"
            >
            标签
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/search/"
            rel="noopener noreferrer"
            target="_self"
            >
            搜索
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/link/"
            rel="noopener noreferrer"
            target="_self"
            >
            友链
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/about/"
            rel="noopener noreferrer"
            target="_self"
            >
            关于
          </a>
        </li>
      
    </ul>
  </div>


</div>


  <div id="toc" class="toc-article">
    <strong class="toc-title">文章目录<i class="iconfont toc-title" style="display:inline-block;color:#87998d;width:20px;height:20px;">&#xf004b;</i></strong>
    <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#一、前言"><span class="toc-text">一、前言</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#二、ES2015"><span class="toc-text">二、ES2015</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#声明"><span class="toc-text">声明</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#解构赋值"><span class="toc-text">解构赋值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#字符串扩展"><span class="toc-text">字符串扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#数值扩展"><span class="toc-text">数值扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#对象扩展"><span class="toc-text">对象扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#数组扩展"><span class="toc-text">数组扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#函数扩展"><span class="toc-text">函数扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#正则扩展"><span class="toc-text">正则扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Symbol"><span class="toc-text">Symbol</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Set"><span class="toc-text">Set</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Map"><span class="toc-text">Map</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Proxy"><span class="toc-text">Proxy</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Reflect"><span class="toc-text">Reflect</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Class"><span class="toc-text">Class</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Module"><span class="toc-text">Module</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Iterator"><span class="toc-text">Iterator</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Promise"><span class="toc-text">Promise</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Generator"><span class="toc-text">Generator</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ES2016"><span class="toc-text">ES2016</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#数值扩展-1"><span class="toc-text">数值扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#数组扩展-1"><span class="toc-text">数组扩展</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ES2017"><span class="toc-text">ES2017</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#字符串扩展-1"><span class="toc-text">字符串扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#函数扩展-1"><span class="toc-text">函数扩展</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ES2018"><span class="toc-text">ES2018</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#字符串扩展-2"><span class="toc-text">字符串扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#正则扩展-1"><span class="toc-text">正则扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Promise-1"><span class="toc-text">Promise</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Async"><span class="toc-text">Async</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ES2019"><span class="toc-text">ES2019</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#字符串扩展-3"><span class="toc-text">字符串扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#对象扩展-1"><span class="toc-text">对象扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#数组扩展-2"><span class="toc-text">数组扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#函数扩展-2"><span class="toc-text">函数扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Symbol-1"><span class="toc-text">Symbol</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ES提案"><span class="toc-text">ES提案</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#声明-1"><span class="toc-text">声明</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#数值扩展-2"><span class="toc-text">数值扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#对象扩展-2"><span class="toc-text">对象扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#函数扩展-3"><span class="toc-text">函数扩展</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Proxy-1"><span class="toc-text">Proxy</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Realm"><span class="toc-text">Realm</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Class-1"><span class="toc-text">Class</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Module-1"><span class="toc-text">Module</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Async-1"><span class="toc-text">Async</span></a></li></ol></li></ol>
  </div>
  




<div class="content content-post CENTER">
   <!-- canvas 彩带 -->
<canvas id="evanyou" width="1302" height="678" style="position: fixed;width: 100%;height: 100%;top: 0;left:0;z-index:-1;"></canvas>

<article id="post-es6-review-summary" class="article article-type-post" itemprop="blogPost">
  <header class="article-header" style="position:relative;">
    <h1 class="post-title">ES2015/ES2016/ES2017/ES2018/ES2019</h1>

    <div class="article-meta">
      <span>
        <i class="icon-calendar"></i>
        <span>2019.11.17</span>
      </span>

      
        <span class="article-author">
          <i class="icon-user"></i>
          <span>Poetry</span>
        </span>
      

      
  <span class="article-category">
    <i class="icon-list"></i>
    <a class="article-category-link" href="/categories/Front-End/">Front-End</a>
  </span>



      

      
      <i class="fa fa-eye"></i> 
        <span id="busuanzi_container_page_pv">
           &nbsp热度 <span id="busuanzi_value_page_pv">
           <i class="fa fa-spinner fa-spin"></i></span>℃
        </span>
      
      
       
          <span class="post-count">
            <i class="fa fa-file-word-o"></i>&nbsp
            <span>字数统计 13.4k字</span>
          </span>

          <span class="post-count">
            <i class="fa fa-columns"></i>&nbsp
            <span>阅读时长 50分</span>
          </span>
      
      
    </div>

    <i class="iconfont" id="toc-eye" style="display:inline-block;color:#b36619;position:absolute;top:0;right:0;cursor:pointer;
    font-size: 24px;">&#xe61c;</i>

  </header>

  <div class="article-content">
    
      <div id="container">
        <p><img src="https://poetries1.gitee.io/img-repo/2019/11/123.png" alt></p>
<h2 id="一、前言"><a href="#一、前言" class="headerlink" title="一、前言"></a>一、前言</h2><ul>
<li><code>ES6</code>是<code>ECMA</code>为<code>JavaScript</code>制定的第6个标准版本</li>
<li>标准委员会最终决定，标准在每年6月正式发布并作为当年的正式版本，接下来的时间里就在此版本的基础上进行改动，直到下一年6月草案就自然变成新一年的版本，这样一来就无需以前的版本号，只要用年份标记即可。<code>ECMAscript 2015</code>是在2015年6月发布ES6的第一个版本。以此类推，<code>ECMAscript</code> 2016是ES6的第二个版本、 ECMAscript 2017是ES6的第三个版本。ES6既是一个历史名词也是一个泛指，含义是5.1版本以后的JavaScript下一代标准，目前涵盖了<code>ES2015</code>、<code>ES2016</code>、<code>ES2017</code>、<code>ES2018</code>、<code>ES2019</code></li>
</ul>
<blockquote>
<p>所以有些文章上提到的ES7(实质上是ES2016)、ES8(实质上是ES2017)、ES9(实质上是ES2018)、ES10(实质上是ES2019)，实质上都是一些不规范的概念。从ES1到ES6，每个标准都是花了好几年甚至十多年才制定下来，你一个ES6到ES7，ES7到ES8，才用了一年，按照这样的定义下去，那不是很快就ES20了。用正确的概念来说ES6目前涵盖了ES2015、ES2016、ES2017、ES2018、ES2019</p>
</blockquote>
<p><img src="https://poetries1.gitee.io/img-repo/2019/11/124.png" alt></p>
<h2 id="二、ES2015"><a href="#二、ES2015" class="headerlink" title="二、ES2015"></a>二、ES2015</h2><p><img src="https://poetries1.gitee.io/img-repo/2019/11/125.png" alt></p>
<h3 id="声明"><a href="#声明" class="headerlink" title="声明"></a>声明</h3><ul>
<li><code>const</code>命令：声明常量</li>
<li><code>let</code>命令：声明变量</li>
</ul>
<blockquote>
<p>作用</p>
</blockquote>
<p><strong>作用域</strong></p>
<ul>
<li>全局作用域</li>
<li>函数作用域：<code>function() {}</code></li>
<li>块级作用域：<code>{}</code></li>
</ul>
<p><strong>作用范围</strong></p>
<ul>
<li><code>var</code>命令在全局代码中执行</li>
<li><code>const</code>命令和<code>let</code>命令只能在代码块中执行</li>
</ul>
<p><strong>赋值使用</strong></p>
<ul>
<li><code>const</code>命令声明常量后必须立马赋值</li>
<li><code>let</code>命令声明变量后可立马赋值或使用时赋值</li>
</ul>
<blockquote>
<p>声明方法：<code>var</code>、<code>const</code>、<code>let</code>、<code>function</code>、<code>class</code>、<code>import</code></p>
</blockquote>
<p><strong>重点难点</strong></p>
<ul>
<li>不允许重复声明</li>
<li>未定义就使用会报错：<code>const</code>命令和<code>let</code>命令不存在变量提升</li>
<li>暂时性死区：在代码块内使用let命令声明变量之前，该变量都不可用</li>
</ul>
<h3 id="解构赋值"><a href="#解构赋值" class="headerlink" title="解构赋值"></a>解构赋值</h3><ul>
<li>字符串解构：<code>const [a, b, c, d, e] = &quot;hello&quot;</code></li>
<li>数值解构：<code>const { toString: s } = 123</code></li>
<li>布尔值解构：<code>const { toString: b } = true</code></li>
</ul>
<p><strong>对象解构</strong></p>
<ul>
<li>形式：<code>const { x, y } = { x: 1, y: 2 }</code></li>
<li>默认：<code>const { x, y = 2 } = { x: 1 }</code></li>
<li>改名：<code>const { x, y: z } = { x: 1, y: 2 }</code></li>
</ul>
<p><strong>数组解构</strong></p>
<ul>
<li>规则：数据结构具有<code>Iterator</code>接口可采用数组形式的解构赋值</li>
<li>形式：<code>const [x, y] = [1, 2]</code></li>
<li>默认：<code>const [x, y = 2] = [1]</code></li>
</ul>
<p><strong>函数参数解构</strong></p>
<ul>
<li>数组解构：<code>function Func([x = 0, y = 1]) {}</code></li>
<li>对象解构：<code>function Func({ x = 0, y = 1 } = {}) {}</code></li>
</ul>
<p><strong>应用场景</strong></p>
<ul>
<li>交换变量值：<code>[x, y] = [y, x]</code></li>
<li>返回函数多个值：<code>const [x, y, z] = Func()</code></li>
<li>定义函数参数：<code>Func([1, 2])</code></li>
<li>提取JSON数据：<code>const { name, version } = packageJson</code></li>
<li>定义函数参数默认值：<code>function Func({ x = 1, y = 2 } = {}) {}</code></li>
<li>遍历Map结构：<code>for (let [k, v] of Map) {}</code></li>
<li>输入模块指定属性和方法：<code>const { readFile, writeFile } = require(&quot;fs&quot;)</code></li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li>匹配模式：只要等号两边的模式相同，左边的变量就会被赋予对应的值</li>
<li>解构赋值规则：只要等号右边的值不是对象或数组，就先将其转为对象</li>
<li>解构默认值生效条件：属性值严格等于undefined</li>
<li>解构遵循匹配模式</li>
<li>解构不成功时变量的值等于<code>undefined</code></li>
<li><code>undefined</code>和<code>null</code>无法转为对象，因此无法进行解构</li>
</ul>
<h3 id="字符串扩展"><a href="#字符串扩展" class="headerlink" title="字符串扩展"></a>字符串扩展</h3><ul>
<li><code>Unicode</code>表示法：大括号包含表示<code>Unicode</code>字符(<code>\u{0xXX}</code>或<code>\u{0XXX}</code>)</li>
<li>字符串遍历：可通过for-of遍历字符串</li>
<li>字符串模板：可单行可多行可插入变量的增强版字符串</li>
<li>标签模板：函数参数的特殊调用</li>
<li><code>String.raw()</code>：返回把字符串所有变量替换且对斜杠进行转义的结果</li>
<li><code>String.fromCodePoint()</code>：返回码点对应字符</li>
<li><code>codePointAt()</code>：返回字符对应码点(<code>String.fromCodePoint()</code>的逆操作)</li>
<li><code>normalize()</code>：把字符的不同表示方法统一为同样形式，返回新字符串(Unicode正规化)</li>
<li><code>repeat()</code>：把字符串重复n次，返回新字符串</li>
<li><code>matchAll()</code>：返回正则表达式在字符串的所有匹配</li>
<li><code>includes()</code>：是否存在指定字符串</li>
<li><code>startsWith()</code>：是否存在字符串头部指定字符串</li>
<li><code>endsWith()</code>：是否存在字符串尾部指定字符串</li>
</ul>
<p><strong>重点难点</strong></p>
<blockquote>
<p>以上扩展方法均可作用于由4个字节储存的<code>Unicode</code>字符上</p>
</blockquote>
<h3 id="数值扩展"><a href="#数值扩展" class="headerlink" title="数值扩展"></a>数值扩展</h3><ul>
<li>二进制表示法：0b或0B开头表示二进制(<code>0bXX</code>或<code>0BXX</code>)</li>
<li>八进制表示法：0o或0O开头表示二进制(<code>0oXX</code>或<code>0OXX</code>)</li>
<li><code>Number.EPSILON</code>：数值最小精度</li>
<li><code>Number.MIN_SAFE_INTEGER</code>：最小安全数值(<code>-2^53</code>)</li>
<li><code>Number.MAX_SAFE_INTEGER</code>：最大安全数值(<code>2^53</code>)</li>
<li><code>Number.parseInt()</code>：返回转换值的整数部分</li>
<li><code>Number.parseFloat()</code>：返回转换值的浮点数部分</li>
<li><code>Number.isFinite()</code>：是否为有限数值</li>
<li><code>Number.isNaN()</code>：是否为<code>NaN</code></li>
<li><code>Number.isInteger()</code>：是否为整数</li>
<li><code>Number.isSafeInteger()</code>：是否在数值安全范围内</li>
<li><code>Math.trunc()</code>：返回数值整数部分</li>
<li><code>Math.sign()</code>：返回数值类型(正数1、负数-1、零0)</li>
<li><code>Math.cbrt()</code>：返回数值立方根</li>
<li><code>Math.clz32()</code>：返回数值的32位无符号整数形式</li>
<li><code>Math.imul()</code>：返回两个数值相乘</li>
<li><code>Math.fround()</code>：返回数值的32位单精度浮点数形式</li>
<li><code>Math.hypot()</code>：返回所有数值平方和的平方根</li>
<li><code>Math.expm1()</code>：返回<code>e^n - 1</code></li>
<li><code>Math.log1p()</code>：返回<code>1 + n</code>的自然对数(<code>Math.log(1 + n)</code>)</li>
<li><code>Math.log10()</code>：返回以10为底的n的对数</li>
<li><code>Math.log2()</code>：返回以2为底的n的对数</li>
<li><code>Math.sinh()</code>：返回n的双曲正弦</li>
<li><code>Math.cosh()</code>：返回n的双曲余弦</li>
<li><code>Math.tanh()</code>：返回n的双曲正切</li>
<li><code>Math.asinh()</code>：返回n的反双曲正弦</li>
<li><code>Math.acosh()</code>：返回n的反双曲余弦</li>
<li><code>Math.atanh()</code>：返回n的反双曲正切</li>
</ul>
<h3 id="对象扩展"><a href="#对象扩展" class="headerlink" title="对象扩展"></a>对象扩展</h3><ul>
<li>简洁表示法：直接写入变量和函数作为对象的属性和方法<code>({ prop, method() {} })</code></li>
<li>属性名表达式：字面量定义对象时使用[]定义键(<code>[prop]</code>，不能与上同时使用)</li>
<li><strong>方法的name属性：返回方法函数名</strong><ul>
<li>取值函数(<code>getter</code>)和存值函数(<code>setter</code>)：<code>get/set</code>函数名(属性的描述对象在get和set上)</li>
<li><code>bind</code>返回的函数：<code>bound</code> 函数名</li>
<li><code>Function</code>构造函数返回的函数实例：<code>anonymous</code></li>
</ul>
</li>
<li>属性的可枚举性和遍历：描述对象的<code>enumerable</code></li>
<li><code>super</code>关键字：指向当前对象的原型对象(只能用在对象的简写方法中<code>method() {}</code>)</li>
<li><code>Object.is()</code>：对比两值是否相等</li>
<li><code>Object.assign()</code>：合并对象(浅拷贝)，返回原对象</li>
<li><code>Object.getPrototypeOf()</code>：返回对象的原型对象</li>
<li><code>Object.setPrototypeOf()</code>：设置对象的原型对象</li>
<li><code>__proto__</code>：返回或设置对象的原型对象</li>
</ul>
<p><strong>属性遍历</strong></p>
<ul>
<li>描述：自身、可继承、可枚举、非枚举、<code>Symbol</code></li>
<li><strong>遍历</strong><ul>
<li><code>for-in</code>：遍历对象自身可继承可枚举属性</li>
<li><code>Object.keys()</code>：返回对象自身可枚举属性的键组成的数组</li>
<li><code>Object.getOwnPropertyNames()</code>：返回对象自身可继承可枚举非枚举属性的键组成的数组</li>
<li><code>Object.getOwnPropertySymbols()</code>：返回对象<code>Symbol</code>属性的键组成的数组</li>
<li><code>Reflect.ownKeys()</code>：返回对象自身可继承可枚举非枚举Symbol属性的键组成的数组</li>
</ul>
</li>
<li><strong>规则</strong><ul>
<li>首先遍历所有数值键，按照数值升序排列</li>
<li>其次遍历所有字符串键，按照加入时间升序排列</li>
<li>最后遍历所有<code>Symbol</code>键，按照加入时间升序排列</li>
</ul>
</li>
</ul>
<h3 id="数组扩展"><a href="#数组扩展" class="headerlink" title="数组扩展"></a>数组扩展</h3><ul>
<li>扩展运算符(<code>...</code>)：转换数组为用逗号分隔的参数序列(<code>[...arr]</code>，相当于<code>rest/spread</code>参数的逆运算)</li>
<li><code>Array.from()</code>：转换具有<code>Iterator</code>接口的数据结构为真正数组，返回新数组<ul>
<li>类数组对象：包含<code>length</code>的对象、<code>Arguments</code>对象、<code>NodeList</code>对象</li>
<li>可遍历对象：<code>String</code>、<code>Set</code>结构、<code>Map</code>结构、<code>Generator</code>函数</li>
</ul>
</li>
<li><code>Array.of()</code>：转换一组值为真正数组，返回新数组</li>
<li><code>copyWithin()</code>：把指定位置的成员复制到其他位置，返回原数组</li>
<li><code>find()</code>：返回第一个符合条件的成员</li>
<li><code>findIndex()</code>：返回第一个符合条件的成员索引值</li>
<li><code>fill()</code>：根据指定值填充整个数组，返回原数组</li>
<li><code>keys()</code>：返回以索引值为遍历器的对象</li>
<li><code>values()</code>：返回以属性值为遍历器的对象</li>
<li><code>entries()</code>：返回以索引值和属性值为遍历器的对象</li>
<li>数组空位：ES6明确将数组空位转为<code>undefined</code>(空位处理规不一，建议避免出现)</li>
</ul>
<p><strong>扩展应用</strong></p>
<ul>
<li>克隆数组：<code>const arr = [...arr1]</code></li>
<li>合并数组：<code>const arr = [...arr1, ...arr2]</code></li>
<li>拼接数组：<code>arr.push(...arr1)</code></li>
<li>代替<code>apply</code>：<code>Math.max.apply(null, [x, y]) =&gt; Math.max(...[x, y])</code></li>
<li>转换字符串为数组：<code>[...&quot;hello&quot;]</code></li>
<li>转换类数组对象为数组：<code>[...Arguments, ...NodeList]</code></li>
<li>转换可遍历对象为数组：<code>[...String, ...Set, ...Map, ...Generator]</code></li>
<li>与数组解构赋值结合：<code>const [x, ...rest/spread] = [1, 2, 3]</code></li>
<li>计算<code>Unicode</code>字符长度：<code>Array.from(&quot;hello&quot;).length =&gt; [...&quot;hello&quot;].length</code></li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li>使用<code>keys()</code>、<code>values()</code>、<code>entries()</code>返回的遍历器对象，可用<code>for-of</code>自动遍历或<code>next()</code>手动遍历</li>
</ul>
<h3 id="函数扩展"><a href="#函数扩展" class="headerlink" title="函数扩展"></a>函数扩展</h3><ul>
<li><strong>参数默认值：为函数参数指定默认值</strong><ul>
<li>形式：<code>function Func(x = 1, y = 2) {}</code></li>
<li>参数赋值：惰性求值(函数调用后才求值)</li>
<li>参数位置：尾参数</li>
<li>参数作用域：函数作用域</li>
<li>声明方式：默认声明，不能用<code>const</code>或<code>let</code>再次声明</li>
<li><code>length</code>：返回没有指定默认值的参数个数</li>
<li>与解构赋值默认值结合：<code>function Func({ x = 1, y = 2 } = {}) {}</code>  </li>
<li><strong>应用</strong><ul>
<li>指定某个参数不得省略，省略即抛出错误：<code>function Func(x = throwMissing()) {}</code></li>
<li>将参数默认值设为<code>undefined</code>，表明此参数可省略：<code>Func(undefined, 1)</code></li>
</ul>
</li>
</ul>
</li>
<li><strong>rest/spread参数(…)：返回函数多余参数</strong><ul>
<li>形式：以数组的形式存在，之后不能再有其他参数</li>
<li>作用：代替<code>Arguments</code>对象</li>
<li><code>length</code>：返回没有指定默认值的参数个数但不包括<code>rest/spread</code>参数</li>
</ul>
</li>
<li><strong>严格模式：在严格条件下运行JS</strong><ul>
<li>应用：只要函数参数使用默认值、解构赋值、扩展运算符，那么函数内部就不能显式设定为严格模式</li>
</ul>
</li>
<li><strong>name属性</strong>：返回函数的函数名<ul>
<li>将匿名函数赋值给变量：空字符串(ES5)、变量名(ES6)</li>
<li>将具名函数赋值给变量：函数名(ES5和ES6)</li>
<li><code>bind</code>返回的函数：<code>bound</code> 函数名(ES5和ES6)</li>
<li><code>Function</code>构造函数返回的函数实例：<code>anonymous</code>(ES5和ES6)</li>
</ul>
</li>
<li><strong>箭头函数(=&gt;)：函数简写</strong><ul>
<li>无参数：<code>() =&gt; {}</code></li>
<li>单个参数：<code>x =&gt; {}</code></li>
<li>多个参数：<code>(x, y) =&gt; {}</code></li>
<li>解构参数：<code>({x, y}) =&gt; {}</code></li>
<li>嵌套使用：部署管道机制</li>
<li><code>this</code>指向固定化<ul>
<li>并非因为内部有绑定<code>this</code>的机制，而是根本没有自己的<code>this</code>，导致内部的<code>this</code>就是外层代码块的<code>this</code></li>
<li>因为没有<code>this</code>，因此不能用作构造函数</li>
</ul>
</li>
</ul>
</li>
<li><strong>尾调用优化：只保留内层函数的调用帧</strong><ul>
<li><strong>尾调用</strong><ul>
<li>定义：某个函数的最后一步是调用另一个函数</li>
<li>形式：<code>function f(x) { return g(x); }</code></li>
</ul>
</li>
<li><strong>尾递归</strong><ul>
<li>定义：函数尾调用自身</li>
<li>作用：只要使用尾递归就不会发生栈溢出，相对节省内存</li>
<li>实现：把所有用到的内部变量改写成函数的参数并使用参数默认值</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>箭头函数误区</strong></p>
<ul>
<li>函数体内的<code>this</code>是定义时所在的对象而不是使用时所在的对象</li>
<li>可让<code>this</code>指向固定化，这种特性很有利于封装回调函数</li>
<li>不可当作构造函数，因此箭头函数不可使用<code>new</code>命令</li>
<li>不可使用<code>yield</code>命令，因此箭头函数不能用作<code>Generator</code>函数</li>
<li>不可使用<code>Arguments</code>对象，此对象在函数体内不存在(可用<code>rest/spread</code>参数代替)</li>
<li>返回对象时必须在对象外面加上括号</li>
</ul>
<h3 id="正则扩展"><a href="#正则扩展" class="headerlink" title="正则扩展"></a>正则扩展</h3><ul>
<li><strong>变更<code>RegExp</code>构造函数入参</strong>：允许首参数为正则对象，尾参数为正则修饰符(返回的正则表达式会忽略原正则表达式的修饰符)</li>
<li><strong>正则方法调用变更</strong>：字符串对象的<code>match()</code>、<code>replace()</code>、<code>search()</code>、<code>split()</code>内部调用转为调用<code>RegExp</code>实例对应的<code>RegExp.prototype[Symbol.方法]</code></li>
<li><strong>u修饰符</strong>：<code>Unicode</code>模式修饰符，正确处理大于<code>\uFFFF</code>的<code>Unicode</code>字符<ul>
<li>点字符(<code>.</code>)</li>
<li><code>Unicode</code>表示法</li>
<li>量词</li>
<li>预定义模式</li>
<li><code>i</code>修饰符</li>
<li>转义</li>
</ul>
</li>
<li><strong>y修饰符</strong>：粘连修饰符，确保匹配必须从剩余的第一个位置开始全局匹配(与g修饰符作用类似)</li>
<li><strong>unicode</strong>：是否设置<code>u</code>修饰符</li>
<li><strong>sticky</strong>：是否设置<code>y</code>修饰符</li>
<li><strong>flags</strong>：正则表达式的修饰符</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li><code>y</code>修饰符隐含头部匹配标志<code>^</code></li>
<li>单单一个y修饰符对<code>match()</code>只能返回第一个匹配，必须与g修饰符联用才能返回所有匹配</li>
</ul>
<h3 id="Symbol"><a href="#Symbol" class="headerlink" title="Symbol"></a>Symbol</h3><ul>
<li>定义：独一无二的值</li>
<li>声明：<code>const set = Symbol(str)</code></li>
<li>入参：字符串(可选)</li>
</ul>
<p><strong>方法</strong></p>
<ul>
<li><code>Symbol()</code>：创建以参数作为描述的Symbol值(不登记在全局环境)</li>
<li><code>Symbol.for()</code>：创建以参数作为描述的Symbol值，如存在此参数则返回原有的Symbol值(先搜索后创建，登记在全局环境)</li>
<li><code>Symbol.keyFor()</code>：返回已登记的<code>Symbol</code>值的描述(只能返回<code>Symbol.for()</code>的<code>key</code>)</li>
<li><code>Object.getOwnPropertySymbols()</code>：返回对象中所有用作属性名的<code>Symbol</code>值的数组</li>
</ul>
<p><strong>内置</strong></p>
<ul>
<li><code>Symbol.hasInstance</code>：指向一个内部方法，当其他对象使用<code>instanceof</code>运算符判断是否为此对象的实例时会调用此方法</li>
<li><code>Symbol.isConcatSpreadable</code>：指向一个布尔值，定义对象用于<code>Array.prototype.concat()</code>时是否可展开</li>
<li><code>Symbol.species</code>：指向一个构造函数，当实例对象使用自身构造函数时会调用指定的构造函数</li>
<li><code>Symbol.match</code>：指向一个函数，当实例对象被<code>String.prototype.match()</code>调用时会重新定义<code>match()</code>的行为</li>
<li><code>Symbol.replace</code>：指向一个函数，当实例对象被<code>String.prototype.replace()</code>调用时会重新定义<code>replace()</code>的行为</li>
<li><code>Symbol.search</code>：指向一个函数，当实例对象被<code>String.prototype.search()</code>调用时会重新定义<code>search()</code>的行为</li>
<li><code>Symbol.split</code>：指向一个函数，当实例对象被<code>String.prototype.split()</code>调用时会重新定义<code>split()</code>的行为</li>
<li><code>Symbol.iterator</code>：指向一个默认遍历器方法，当实例对象执行<code>for-of</code>时会调用指定的默认遍历器</li>
<li><code>Symbol.toPrimitive</code>：指向一个函数，当实例对象被转为原始类型的值时会返回此对象对应的原始类型值</li>
<li><code>Symbol.toStringTag</code>：指向一个函数，当实例对象被<code>Object.prototype.toString()</code>调用时其返回值会出现在<code>toString()</code>返回的字符串之中表示对象的类型</li>
<li><code>Symbol.unscopables</code>：指向一个对象，指定使用<code>with</code>时哪些属性会被<code>with</code>环境排除</li>
</ul>
<p><strong>数据类型</strong></p>
<ul>
<li><code>Undefined</code></li>
<li><code>Null</code></li>
<li><code>String</code></li>
<li><code>Number</code></li>
<li><code>Boolean</code></li>
<li><code>Object</code>(包含<code>Array</code>、<code>Function</code>、<code>Date</code>、<code>RegExp</code>、<code>Error</code>)</li>
<li><code>Symbol</code></li>
</ul>
<p><strong>应用场景</strong></p>
<ul>
<li>唯一化对象属性名：属性名属于<code>Symbol</code>类型，就都是独一无二的，可保证不会与其他属性名产生冲突</li>
<li>消除魔术字符串：在代码中多次出现且与代码形成强耦合的某一个具体的字符串或数值</li>
<li>遍历属性名：无法通过<code>for-in</code>、<code>for-of</code>、<code>Object.keys()</code>、<code>Object.getOwnPropertyNames()</code>、<code>JSON.stringify()</code>返回，只能通过<code>Object.getOwnPropertySymbols</code>返回<br>启用模块的<code>Singleton</code>模式：调用一个类在任何时候返回同一个实例(<code>window</code>和<code>global</code>)，- 使用<code>Symbol.for()</code>来模拟全局的<code>Singleton</code>模式</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li><code>Symbol()</code>生成一个原始类型的值不是对象，因此<code>Symbol()</code>前不能使用<code>new</code>命令</li>
<li><code>Symbol()</code>参数表示对当前<code>Symbol</code>值的描述，相同参数的<code>Symbol()</code>返回值不相等</li>
<li><code>Symbol</code>值不能与其他类型的值进行运算</li>
<li><code>Symbol</code>值可通过<code>String()</code>或<code>toString()</code>显式转为字符串</li>
<li><code>Symbol</code>值作为对象属性名时，此属性是公开属性，但不是私有属性</li>
<li><code>Symbol</code>值作为对象属性名时，只能用方括号运算符(<code>[]</code>)读取，不能用点运算符(<code>.</code>)读取`</li>
<li><code>Symbol</code>值作为对象属性名时，不会被常规方法遍历得到，可利用此特性为对象定义非私有但又只用于内部的方法</li>
</ul>
<h3 id="Set"><a href="#Set" class="headerlink" title="Set"></a>Set</h3><p><strong>Set</strong></p>
<ul>
<li>定义：类似于数组的数据结构，成员值都是唯一且没有重复的值</li>
<li>声明：<code>const set = new Set(arr)</code></li>
<li>入参：具有<code>Iterator</code>接口的数据结构</li>
<li>属性<ul>
<li><code>constructor</code>：构造函数，返回<code>Set</code></li>
<li><code>size</code>：返回实例成员总数</li>
</ul>
</li>
<li>方法<ul>
<li><code>add()</code>：添加值，返回实例</li>
<li><code>delete()</code>：删除值，返回布尔值</li>
<li><code>has()</code>：检查值，返回布尔值</li>
<li><code>clear()</code>：清除所有成员</li>
<li><code>keys()</code>：返回以属性值为遍历器的对象</li>
<li><code>values()</code>：返回以属性值为遍历器的对象</li>
<li><code>entries()</code>：返回以属性值和属性值为遍历器的对象</li>
<li><code>forEach()</code>：使用回调函数遍历每个成员</li>
</ul>
</li>
</ul>
<p><strong>应用场景</strong></p>
<ul>
<li>去重字符串：<code>[...new Set(str)].join(&quot;&quot;)</code></li>
<li>去重数组：<code>[...new Set(arr)]或Array.from(new Set(arr))</code></li>
<li>集合数组<ul>
<li>声明：<code>const a = new Set(arr1)、const b = new Set(arr2)</code></li>
<li>并集：<code>new Set([...a, ...b])</code></li>
<li>交集：<code>new Set([...a].filter(v =&gt; b.has(v)))</code></li>
<li>差集：<code>new Set([...a].filter(v =&gt; !b.has(v)))</code></li>
</ul>
</li>
<li>映射集合<ul>
<li>声明：<code>let set = new Set(arr)</code></li>
<li>映射：<code>set = new Set([...set].map(v =&gt; v * 2))</code>或<code>set = new Set(Array.from(set, v =&gt; v * 2))</code></li>
</ul>
</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li>遍历顺序：插入顺序</li>
<li>没有键只有值，可认为键和值两值相等</li>
<li>添加多个<code>NaN</code>时，只会存在一个<code>NaN</code></li>
<li>添加相同的对象时，会认为是不同的对象</li>
<li>添加值时不会发生类型转换<code>(5 !== &quot;5&quot;)</code></li>
<li><code>keys()</code>和<code>values()</code>的行为完全一致，<code>entries()</code>返回的遍历器同时包括键和值且两值相等</li>
</ul>
<p><strong>WeakSet</strong></p>
<ul>
<li>定义：和<code>Set</code>结构类似，成员值只能是对象</li>
<li>声明：<code>const set = new WeakSet(arr)</code></li>
<li>入参：具有`Iterator接口的数据结构</li>
<li>属性<ul>
<li><code>constructor</code>：构造函数，返回<code>WeakSet</code></li>
</ul>
</li>
<li>方法<ul>
<li><code>add()</code>：添加值，返回实例</li>
<li><code>delete()</code>：删除值，返回布尔值</li>
<li><code>has()</code>：检查值，返回布尔值</li>
</ul>
</li>
</ul>
<p><strong>应用场景</strong></p>
<ul>
<li>储存<code>DOM</code>节点：<code>DOM</code>节点被移除时自动释放此成员，不用担心这些节点从文档移除时会引发内存泄漏</li>
<li>临时存放一组对象或存放跟对象绑定的信息：只要这些对象在外部消失，它在<code>WeakSe</code>t结构中的引用就会自动消</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li>成员都是弱引用，垃圾回收机制不考虑<code>WeakSet</code>结构对此成员的引用</li>
<li>成员不适合引用，它会随时消失，因此ES6规定<code>WeakSet</code>结构不可遍历</li>
<li>其他对象不再引用成员时，垃圾回收机制会自动回收此成员所占用的内存，不考虑此成员是否还存在于<code>WeakSet</code>结构中</li>
</ul>
<h3 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h3><p><strong>Map</strong></p>
<ul>
<li>定义：类似于对象的数据结构，成员键可以是任何类型的值</li>
<li>声明：<code>const set = new Map(arr)</code></li>
<li>入参：具有<code>Iterator</code>接口且每个成员都是一个双元素数组的数据结构</li>
<li>属性<ul>
<li><code>constructor</code>：构造函数，返回<code>Map</code></li>
<li><code>size</code>：返回实例成员总数</li>
</ul>
</li>
<li>方法<ul>
<li><code>get()</code>：返回键值对</li>
<li><code>set()</code>：添加键值对，返回实例</li>
<li><code>delete()</code>：删除键值对，返回布尔值</li>
<li><code>has()</code>：检查键值对，返回布尔值</li>
<li><code>clear()</code>：清除所有成员</li>
<li><code>keys()</code>：返回以键为遍历器的对象</li>
<li><code>values()</code>：返回以值为遍历器的对象</li>
<li><code>entries()</code>：返回以键和值为遍历器的对象</li>
<li><code>forEach()</code>：使用回调函数遍历每个成员</li>
</ul>
</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li>遍历顺序：插入顺序</li>
<li>对同一个键多次赋值，后面的值将覆盖前面的值</li>
<li>对同一个对象的引用，被视为一个键</li>
<li>对同样值的两个实例，被视为两个键</li>
<li>键跟内存地址绑定，只要内存地址不一样就视为两个键</li>
<li>添加多个以<code>NaN</code>作为键时，只会存在一个以<code>NaN</code>作为键的值</li>
<li><code>Object</code>结构提供字符串—值的对应，<code>Map</code>结构提供值—值的对应</li>
</ul>
<p><strong>WeakMap</strong></p>
<ul>
<li>定义：和<code>Map</code>结构类似，成员键只能是对象</li>
<li>声明：<code>const set = new WeakMap(arr)</code></li>
<li>入参：具有Iterator接口且每个成员都是一个双元素数组的数据结构</li>
<li>属性<ul>
<li><code>constructor</code>：构造函数，返回<code>WeakMap</code></li>
</ul>
</li>
<li>方法<ul>
<li><code>get()</code>：返回键值对</li>
<li><code>set()</code>：添加键值对，返回实例</li>
<li><code>delete()</code>：删除键值对，返回布尔值</li>
<li><code>has()</code>：检查键值对，返回布尔值</li>
</ul>
</li>
</ul>
<p><strong>应用场景</strong></p>
<ul>
<li>储存DOM节点：DOM节点被移除时自动释放此成员键，不用担心这些节点从文档移除时会引发内存泄漏</li>
<li>部署私有属性：内部属性是实例的弱引用，删除实例时它们也随之消失，不会造成内存泄漏</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li>成员键都是弱引用，垃圾回收机制不考虑<code>WeakMap</code>结构对此成员键的引用</li>
<li>成员键不适合引用，它会随时消失，因此ES6规定<code>WeakMap</code>结构不可遍历</li>
<li>其他对象不再引用成员键时，垃圾回收机制会自动回收此成员所占用的内存，不考虑此成员是否还存在于<code>WeakMap</code>结构中</li>
<li>一旦不再需要，成员会自动消失，不用手动删除引用</li>
<li>弱引用的只是键而不是值，值依然是正常引用</li>
<li>即使在外部消除了成员键的引用，内部的成员值依然存在</li>
</ul>
<h3 id="Proxy"><a href="#Proxy" class="headerlink" title="Proxy"></a>Proxy</h3><ul>
<li>定义：修改某些操作的默认行为</li>
<li>声明：<code>const proxy = new Proxy(target, handler)</code></li>
<li>入参<ul>
<li><code>target</code>：拦截的目标对象</li>
<li><code>handler</code>：定制拦截行为</li>
</ul>
</li>
<li><p>方法</p>
<ul>
<li><code>Proxy.revocable()</code>：返回可取消的<code>Proxy</code>实例(返回<code>{ proxy, revoke }</code>，通过<code>revoke()</code>取消代理)</li>
</ul>
</li>
<li><p>拦截方式</p>
<ul>
<li><code>get()</code>：拦截对象属性读取</li>
<li><code>set()</code>：拦截对象属性设置，返回布尔值</li>
<li><code>has()</code>：拦截对象属性检查<code>k in obj</code>，返回布尔值</li>
<li><code>deleteProperty()</code>：拦截对象属性删除<code>delete obj[k]</code>，返回布尔值</li>
<li><code>defineProperty()</code>：拦截对象属性定义<code>Object.defineProperty()</code>、<code>Object.defineProperties()</code>，返回布尔值</li>
<li><code>ownKeys()</code>：拦截对象属性遍历<code>for-in</code>、<code>Object.keys()</code>、<code>Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()</code>，返回数组</li>
<li><code>getOwnPropertyDescriptor()</code>：拦截对象属性描述读取<code>Object.getOwnPropertyDescriptor()</code>，返回对象</li>
<li><code>getPrototypeOf()</code>：拦截对象原型读取<code>instanceof</code>、<code>Object.getPrototypeOf()</code>、<code>Object.prototype.__proto__</code>、<code>Object.prototype.isPrototypeOf()</code>、<code>Reflect.getPrototypeOf()</code>，返回对象</li>
<li><code>setPrototypeOf()</code>：拦截对象原型设置<code>Object.setPrototypeOf()</code>，返回布尔值</li>
<li><code>isExtensible()</code>：拦截对象是否可扩展读取<code>Object.isExtensible()</code>，返回布尔值</li>
<li><code>preventExtensions()</code>：拦截对象不可扩展设置<code>Object.preventExtensions()</code>，返回布尔值</li>
<li><code>apply()</code>：拦截<code>Proxy</code>实例作为函数调用<code>proxy()</code>、<code>proxy.apply()</code>、<code>proxy.call()</code></li>
<li><code>construct()</code>：拦截<code>Proxy</code>实例作为构造函数调用<code>new proxy()</code></li>
</ul>
</li>
</ul>
<p><strong>应用场景</strong></p>
<ul>
<li><code>Proxy.revocable()</code>：不允许直接访问对象，必须通过代理访问，一旦访问结束就收回代理权不允许再次访问</li>
<li><code>get()</code>：读取未知属性报错、读取数组负数索引的值、封装链式操作、生成DOM嵌套节点</li>
<li><code>set()</code>：数据绑定(<code>Vue</code>数据绑定实现原理)、确保属性值设置符合要求、防止内部属性被外部读写</li>
<li><code>has()</code>：隐藏内部属性不被发现、排除不符合属性条件的对象</li>
<li><code>deleteProperty()</code>：保护内部属性不被删除</li>
<li><code>defineProperty()</code>：阻止属性被外部定义</li>
<li><code>ownKeys()</code>：保护内部属性不被遍历</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li>要使<code>Proxy</code>起作用，必须针对实例进行操作，而不是针对目标对象进行操作</li>
<li>没有设置任何拦截时，等同于直接通向原对象</li>
<li>属性被定义为不可读写/扩展/配置/枚举时，使用拦截方法会报错</li>
<li>代理下的目标对象，内部<code>this</code>指向<code>Proxy</code>代理</li>
</ul>
<h3 id="Reflect"><a href="#Reflect" class="headerlink" title="Reflect"></a>Reflect</h3><ul>
<li>定义：保持<code>Object</code>方法的默认行为</li>
<li>方法<ul>
<li><code>get()</code>：返回对象属性</li>
<li><code>set()</code>：设置对象属性，返回布尔值</li>
<li><code>has()</code>：检查对象属性，返回布尔值</li>
<li><code>deleteProperty()</code>：删除对象属性，返回布尔值</li>
<li><code>defineProperty()</code>：定义对象属性，返回布尔值</li>
<li><code>ownKeys()</code>：遍历对象属性，返回数<code>组(Object.getOwnPropertyNames()+Object.getOwnPropertySymbols())</code></li>
<li><code>getOwnPropertyDescriptor()</code>：返回对象属性描述，返回对象</li>
<li><code>getPrototypeOf()</code>：返回对象原型，返回对象</li>
<li><code>setPrototypeOf()</code>：设置对象原型，返回布尔值</li>
<li><code>isExtensible()</code>：返回对象是否可扩展，返回布尔值</li>
<li><code>preventExtensions()</code>：设置对象不可扩展，返回布尔值</li>
<li><code>apply()</code>：绑定<code>this</code>后执行指定函数</li>
<li><code>construct()</code>：调用构造函数创建实例</li>
</ul>
</li>
</ul>
<p><strong>设计目的</strong></p>
<ul>
<li><code>Object</code>属于语言内部的方法放到<code>Reflect</code>上</li>
<li>将某些<code>Object</code>方法报错情况改成返回<code>false</code></li>
<li>让<code>Object</code>操作变成函数行为</li>
<li><code>Proxy</code>与<code>Reflect</code>相辅相成</li>
</ul>
<p><strong>废弃方法</strong></p>
<ul>
<li><code>Object.defineProperty()</code> =&gt; <code>Reflect.defineProperty()</code></li>
<li><code>Object.getOwnPropertyDescriptor()</code> =&gt; <code>Reflect.getOwnPropertyDescriptor()</code></li>
</ul>
<blockquote>
<p>数据绑定：观察者模式</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> observerQueue = <span class="keyword">new</span> <span class="built_in">Set</span>();</span><br><span class="line"><span class="keyword">const</span> observe = <span class="function"><span class="params">fn</span> =&gt;</span> observerQueue.add(fn);</span><br><span class="line"><span class="keyword">const</span> observable = <span class="function"><span class="params">obj</span> =&gt;</span> <span class="keyword">new</span> <span class="built_in">Proxy</span>(obj, &#123;</span><br><span class="line">    <span class="keyword">set</span>(tgt, key, val, receiver) &#123;</span><br><span class="line">        <span class="keyword">const</span> result = <span class="built_in">Reflect</span>.set(tgt, key, val, receiver);</span><br><span class="line">        observerQueue.forEach(<span class="function"><span class="params">v</span> =&gt;</span> v());</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> person = observable(&#123; <span class="attr">age</span>: <span class="number">25</span>, <span class="attr">name</span>: <span class="string">"Yajun"</span> &#125;);</span><br><span class="line"><span class="keyword">const</span> print = <span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="string">`<span class="subst">$&#123;person.name&#125;</span> is <span class="subst">$&#123;person.age&#125;</span> years old`</span>);</span><br><span class="line">observe(print);</span><br><span class="line">person.name = <span class="string">"Joway"</span>;</span><br></pre></td></tr></table></figure>
<h3 id="Class"><a href="#Class" class="headerlink" title="Class"></a>Class</h3><ul>
<li>定义：对一类具有共同特征的事物的抽象(构造函数语法糖)</li>
<li>原理：类本身指向构造函数，所有方法定义在<code>prototype</code>上，可看作构造函数的另一种写法(<code>Class === Class.prototype.constructor</code>)</li>
<li><strong>方法和关键字</strong><ul>
<li><code>constructor()</code>：构造函数，<code>new</code>命令生成实例时自动调用</li>
<li><code>extends</code>：继承父类</li>
<li><code>super</code>：新建父类的this</li>
<li><code>static</code>：定义静态属性方法</li>
<li><code>get</code>：取值函数，拦截属性的取值行为</li>
<li><code>set</code>：存值函数，拦截属性的存值行为</li>
</ul>
</li>
<li><strong>属性</strong><ul>
<li><code>__proto__</code>：构造函数的继承(总是指向父类)</li>
<li><code>__proto__.__proto__</code>：子类的原型的原型，即父类的原型(总是指向父类的<code>__proto__</code>)</li>
<li><code>prototype.__proto__</code>：属性方法的继承(总是指向父类的<code>prototype</code>)</li>
</ul>
</li>
<li><strong>静态属性</strong>：定义类完成后赋值属性，该属性不会被实例继承，只能通过类来调用</li>
<li><strong>静态方法</strong>：使用static定义方法，该方法不会被实例继承，只能通过类来调用(方法中的this指向类，而不是实例)</li>
<li><strong>继承</strong><ul>
<li>实质<ul>
<li>ES5实质：先创造子类实例的<code>this</code>，再将父类的属性方法添加到<code>this</code>上(<code>Parent.apply(this)</code>)</li>
<li><code>ES6</code>实质：先将父类实例的属性方法加到<code>this</code>上(调用<code>super()</code>)，再用子类构造函数修改<code>this</code></li>
<li><code>super</code><ul>
<li>作为函数调用：只能在构造函数中调用<code>super()</code>，内部<code>this</code>指向继承的当前子类(<code>super()</code>调用后才可在构造函数中使用<code>this</code>)</li>
<li>作为对象调用：在普通方法中指向父类的原型对象，在静态方法中指向父类</li>
</ul>
</li>
<li>显示定义：使用<code>constructor() { super(); }</code>定义继承父类，没有书写则显示定义</li>
<li>子类继承父类：子类使用父类的属性方法时，必须在构造函数中调用<code>super()</code>，否则得不到父类的<code>this</code><ul>
<li>父类静态属性方法可被子类继承</li>
<li>类继承父类后，可从<code>super</code>上调用父类静态属性方法</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><strong>实例</strong>：类相当于实例的原型，所有在类中定义的属性方法都会被实例继承<ul>
<li>显式指定属性方法：使用<code>this</code>指定到自身上(使用<code>Class.hasOwnProperty()</code>可检测到)</li>
<li>隐式指定属性方法：直接声明定义在对象原型上(使用<code>Class.__proto__.hasOwnProperty()</code>可检测到)</li>
</ul>
</li>
<li><strong>表达式</strong><ul>
<li>类表达式：<code>const Class = class {}</code></li>
<li><code>name</code>属性：返回紧跟<code>class</code>后的类名</li>
<li>属性表达式：<code>[prop]</code></li>
<li><code>Generator</code>方法：<code>* mothod() {}</code></li>
<li><code>Async</code>方法：<code>async mothod() {}</code></li>
</ul>
</li>
<li><strong>this指向</strong>：解构实例属性或方法时会报错<ul>
<li>绑定<code>this</code>：<code>this.mothod = this.mothod.bind(this)</code></li>
<li>箭头函数：<code>this.mothod = () =&gt; this.mothod()</code></li>
</ul>
</li>
<li><strong>属性定义位置</strong><ul>
<li>定义在构造函数中并使用<code>this</code>指向</li>
<li>定义在类最顶层</li>
</ul>
</li>
<li><strong><code>new.target</code>：确定构造函数是如何调用</strong></li>
</ul>
<p><strong>原生构造函数</strong></p>
<ul>
<li><code>String()</code></li>
<li><code>Number()</code></li>
<li><code>Boolean()</code></li>
<li><code>Array()</code></li>
<li><code>Object()</code></li>
<li><code>Function()</code></li>
<li><code>Date()</code></li>
<li><code>RegExp()</code></li>
<li><code>Error()</code></li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li>在实例上调用方法，实质是调用原型上的方法</li>
<li><code>Object.assign()</code>可方便地一次向类添加多个方法<code>(Object.assign(Class.prototype, { ... }))</code></li>
<li>类内部所有定义的方法是不可枚举的(<code>non-enumerable</code>)</li>
<li>构造函数默认返回实例对象(<code>this</code>)，可指定返回另一个对象</li>
<li>取值函数和存值函数设置在属性的<code>Descriptor</code>对象上</li>
<li>类不存在变量提升</li>
<li>利用<code>new.target === Class</code>写出不能独立使用必须继承后才能使用的类</li>
<li>子类继承父类后，<code>this</code>指向子类实例，通过<code>super</code>对某个属性赋值，赋值的属性会变成子类实例的属性</li>
<li>使用<code>super</code>时，必须显式指定是作为函数还是作为对象使用</li>
<li><code>extends</code>不仅可继承类还可继承原生的构造函数</li>
</ul>
<p><strong>私有属性方法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> name = <span class="built_in">Symbol</span>(<span class="string">"name"</span>);</span><br><span class="line"><span class="keyword">const</span> print = <span class="built_in">Symbol</span>(<span class="string">"print"</span>);</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(age) &#123;</span><br><span class="line">        <span class="keyword">this</span>[name] = <span class="string">"Bruce"</span>;</span><br><span class="line">        <span class="keyword">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line">    [print]() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">`<span class="subst">$&#123;<span class="keyword">this</span>[name]&#125;</span> is <span class="subst">$&#123;<span class="keyword">this</span>.age&#125;</span> years old`</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>继承混合类</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">CopyProperties</span>(<span class="params">target, source</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">of</span> <span class="built_in">Reflect</span>.ownKeys(source)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (key !== <span class="string">"constructor"</span> &amp;&amp; key !== <span class="string">"prototype"</span> &amp;&amp; key !== <span class="string">"name"</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> desc = <span class="built_in">Object</span>.getOwnPropertyDescriptor(source, key);</span><br><span class="line">            <span class="built_in">Object</span>.defineProperty(target, key, desc);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">MixClass</span>(<span class="params">...mixins</span>) </span>&#123;</span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">Mix</span> </span>&#123;</span><br><span class="line">        <span class="keyword">constructor</span>() &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">const</span> mixin <span class="keyword">of</span> mixins) &#123;</span><br><span class="line">                CopyProperties(<span class="keyword">this</span>, <span class="keyword">new</span> mixin());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">const</span> mixin <span class="keyword">of</span> mixins) &#123;</span><br><span class="line">        CopyProperties(Mix, mixin);</span><br><span class="line">        CopyProperties(Mix.prototype, mixin.prototype);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Mix;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">MixClass</span>(<span class="title">Person</span>, <span class="title">Kid</span>) </span>&#123;&#125;</span><br></pre></td></tr></table></figure>
<h3 id="Module"><a href="#Module" class="headerlink" title="Module"></a>Module</h3><p><strong>命令</strong></p>
<ul>
<li><code>export</code>：规定模块对外接口<ul>
<li>默认导出：<code>export default Person</code>(导入时可指定模块任意名称，无需知晓内部真实名称)</li>
<li>单独导出：<code>export const name = &quot;Bruce&quot;</code></li>
<li>按需导出：<code>export { age, name, sex }(推荐)</code></li>
<li>改名导出：<code>export { name as newName }</code></li>
</ul>
</li>
<li><code>import</code>：导入模块内部功能<ul>
<li>默认导入：<code>import Person from &quot;person&quot;</code></li>
<li>整体导入：<code>import * as Person from &quot;person&quot;</code></li>
<li>按需导入：<code>import { age, name, sex } from &quot;person&quot;</code></li>
<li>改名导入：<code>import { name as newName } from &quot;person&quot;</code></li>
<li>自执导入：<code>import &quot;person&quot;</code></li>
<li>复合导入：<code>import Person, { name } from &quot;person&quot;</code></li>
</ul>
</li>
<li>复合模式：<code>export</code>命令和<code>import</code>命令结合在一起写成一行，变量实质没有被导入 当前模块，相当于对外转发接口，导致当前模块无法直接使用其导入变量<ul>
<li>默认导入导出：<code>export { default } from &quot;person&quot;</code></li>
<li>整体导入导出：<code>export * from &quot;person&quot;</code></li>
<li>按需导入导出：<code>export { age, name, sex } from &quot;person&quot;</code></li>
<li>改名导入导出：<code>export { name as newName } from &quot;person&quot;</code></li>
<li>具名改默认导入导出：<code>export { name as default } from &quot;person&quot;</code></li>
<li>默认改具名导入导出：<code>export { default as name } from &quot;person&quot;</code></li>
</ul>
</li>
<li>继承：默认导出和改名导出结合使用可使模块具备继承性</li>
<li>设计思想：尽量地静态化，使得编译时就能确定模块的依赖关系，以及输入和输出的变量</li>
<li>严格模式：ES6模块自动采用严格模式(不管模块头部是否添加<code>use strict</code>)</li>
</ul>
<p><strong>模块方案</strong></p>
<ul>
<li><strong>CommonJS</strong>：用于服务器(动态化依赖)</li>
<li><strong>AMD</strong>：用于浏览器(动态化依赖)</li>
<li><strong>CMD</strong>：用于浏览器(动态化依赖)</li>
<li><strong>UMD</strong>：用于浏览器和服务器(动态化依赖)</li>
<li><strong>ESM</strong>：用于浏览器和服务器(静态化依赖)</li>
</ul>
<p><strong>加载方式</strong></p>
<ul>
<li><strong>运行时加载</strong><ul>
<li>定义：整体加载模块生成一个对象，再从对象上获取需要的属性和方法进行加载(全部加载)</li>
<li>影响：只有运行时才能得到这个对象，导致无法在编译时做静态优化</li>
</ul>
</li>
<li><strong>编译时加载</strong></li>
<li>定义：直接从模块中获取需要的属性和方法进行加载(按需加载)</li>
<li>影响：在编译时就完成模块加载，效率比其他方案高，但无法引用模块本身(本身不是对象)，可拓展JS高级语法(宏和类型校验)</li>
</ul>
<p><strong>加载实现</strong></p>
<ul>
<li><strong>传统加载</strong>：通过<code>&lt;script&gt;</code>进行同步或异步加载脚本<ul>
<li>同步加载：<code>&lt;script src=&quot;&quot;&gt;&lt;/script&gt;</code></li>
<li><code>Defer</code>异步加载：<code>&lt;script src=&quot;&quot; defer&gt;&lt;/script&gt;</code>(顺序加载，渲染完再执行)</li>
<li><code>Async</code>异步加载：<code>&lt;script src=&quot;&quot; async&gt;&lt;/script&gt;</code>(乱序加载，下载完就执行)</li>
</ul>
</li>
<li><strong>模块加载</strong>：<code>&lt;script type=&quot;module&quot; src=&quot;&quot;&gt;&lt;/script&gt;</code>(默认是<code>Defer</code>异步加载)</li>
</ul>
<p><strong>CommonJS和ESM的区别</strong></p>
<ul>
<li><code>CommonJS</code>输出值的拷贝，<code>ESM</code>输出值的引用<ul>
<li><code>CommonJS</code>一旦输出一个值，模块内部的变化就影响不到这个值</li>
<li><code>ESM</code>是动态引用且不会缓存值，模块里的变量绑定其所在的模块，等到脚本真正执行时，再根据这个只读引用到被加载的那个模块里去取值</li>
</ul>
</li>
<li><code>CommonJS</code>是运行时加载，<code>ESM</code>是编译时加载<ul>
<li><code>CommonJS</code>加载模块是对象(即<code>module.exports</code>)，该对象只有在脚本运行完才会生成</li>
<li><code>ESM</code>加载模块不是对象，它的对外接口只是一种静态定义，在代码静态解析阶段就会生成</li>
</ul>
</li>
</ul>
<p><strong>Node加载</strong></p>
<ul>
<li>背景：<code>CommonJS</code>和<code>ESM</code>互不兼容，目前解决方案是将两者分开，采用各自的加载方案</li>
<li>区分：要求<code>ESM</code>采用<code>.mjs</code>后缀文件名<ul>
<li><code>require()</code>不能加载<code>.mjs</code>文件，只有<code>import</code>命令才可加载<code>.mjs</code>文件</li>
<li><code>.mjs</code>文件里不能使用<code>require()</code>，必须使用<code>import</code>命令加载文件</li>
</ul>
</li>
<li>驱动：<code>node --experimental-modules file.mjs</code></li>
<li>限制：<code>Node</code>的<code>import</code>命令目前只支持加载本地模块(<code>file:协</code>议)，不支持加载远程模块</li>
<li>加载优先级<ul>
<li>脚本文件省略后缀名：依次尝试加载四个后缀名文件(<code>.mjs</code>、<code>.js</code>、<code>.json</code>、<code>node</code>)</li>
<li>以上不存在：尝试加载<code>package.json</code>的<code>main</code>字段指定的脚本</li>
<li>以上不存在：依次尝试加载名称为<code>index</code>四个后缀名文件(<code>.mjs</code>、<code>.js</code>、<code>.json</code>、<code>node</code>)</li>
<li>以上不存在：报错</li>
</ul>
</li>
<li>不存在的内部变量：<code>arguments</code>、<code>exports</code>、<code>module</code>、<code>require</code>、<code>this</code>、<code>__dirname</code>、<code>__filename</code></li>
<li><code>CommonJS</code>加载<code>ESM</code><ul>
<li>不能使用<code>require()</code>，只能使用<code>import()</code></li>
</ul>
</li>
<li><code>ESM</code>加载<code>CommonJS</code><ul>
<li>自动将<code>module.exports</code>转化成<code>export default</code></li>
<li><code>CommonJS</code>输出缓存机制在ESM加载方式下依然有效</li>
<li>采用<code>import</code>命令加载<code>CommonJS</code>模块时，不允许采用按需导入，应使用默认导入或整体导入</li>
</ul>
</li>
</ul>
<p><strong>循环加载</strong></p>
<ul>
<li>定义：脚本<code>A</code>的执行依赖脚本<code>B</code>，而脚本<code>A</code>的执行又依赖脚本B</li>
<li><strong>加载原理</strong><ul>
<li><code>CommonJS</code>：<code>require()</code>首次加载脚本就会执行整个脚本，在内存里生成一个对象缓存下来，二次加载脚本时直接从缓存中获取</li>
<li><code>ESM</code>：<code>import</code>命令加载变量不会被缓存，而是成为一个指向被加载模块的引用</li>
</ul>
</li>
<li><strong>循环加载</strong><ul>
<li><code>CommonJS</code>：只输出已经执行的部分，还未执行的部分不会输出</li>
<li><code>ESM</code>：需开发者自己保证真正取值时能够取到值(可把变量写成函数形式，函数具有提升作用)</li>
</ul>
</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li><code>ES6</code>模块中，顶层<code>this</code>指向<code>undefined</code>，不应该在顶层代码使用<code>this</code></li>
<li>`一个模块就是一个独立的文件，该文件内部的所有变量，外部无法获取</li>
<li><code>export</code>命令输出的接口与其对应的值是动态绑定关系，即通过该接口可获取模块内部实时的值</li>
<li><code>import</code>命令大括号里的变量名必须与被导入模块对外接口的名称相同</li>
<li><code>import</code>命令输入的变量只读(本质是输入接口)，不允许在加载模块的脚本里改写接口</li>
<li><code>import</code>命令命令具有提升效果，会提升到整个模块的头部，首先执行<br>重复执行同一句import语句，只会执行一次</li>
<li><code>export default</code>命令只能使用一次</li>
<li><code>export default</code>命令导出的整体模块，在执行<code>import</code>命令时其后不能跟大括号</li>
<li><code>export default</code>命令本质是输出一个名为<code>default</code>的变量，后面不能跟变量声明语句</li>
<li><code>export default</code>命令本质是将后面的值赋给名为<code>default</code>的变量，可直接将值写在其后</li>
<li><code>export default</code>命令和<code>export {}</code>命令可同时存在，对应复合导入</li>
<li><code>export</code>命令和<code>import</code>命令可出现在模块任何位置，只要处于模块顶层即可，不能处于块级作用域</li>
<li><code>import()</code>加载模块成功后，此模块会作为一个对象，当作<code>then()</code>的参数，可使用对象解构赋值来获取输出接口</li>
<li>同时动态加载多个模块时，可使用<code>Promise.all()</code>和<code>import()</code>相结合来实现</li>
<li><code>import()</code>和结<code>合async/await</code>来书写同步操作的代码</li>
</ul>
<p><strong>单例模式：跨模块常量</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 常量跨文件共享</span></span><br><span class="line"><span class="comment">// person.js</span></span><br><span class="line"><span class="keyword">const</span> NAME = <span class="string">"Bruce"</span>;</span><br><span class="line"><span class="keyword">const</span> AGE = <span class="number">25</span>;</span><br><span class="line"><span class="keyword">const</span> SEX = <span class="string">"male"</span>;</span><br><span class="line"><span class="keyword">export</span> &#123; AGE, NAME, SEX &#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// file1.js</span></span><br><span class="line"><span class="keyword">import</span> &#123; AGE &#125; <span class="keyword">from</span> <span class="string">"person"</span>;</span><br><span class="line"><span class="built_in">console</span>.log(AGE);</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// file2.js</span></span><br><span class="line"><span class="keyword">import</span> &#123; AGE, NAME, SEX &#125; <span class="keyword">from</span> <span class="string">"person"</span>;</span><br><span class="line"><span class="built_in">console</span>.log(AGE, NAME, SEX);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>默认导入互换整体导入</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import Person from &quot;person&quot;;</span><br><span class="line">console.log(Person.AGE);</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import * as Person from &quot;person&quot;;</span><br><span class="line">console.log(Person.default.AGE);</span><br></pre></td></tr></table></figure>
<h3 id="Iterator"><a href="#Iterator" class="headerlink" title="Iterator"></a>Iterator</h3><ul>
<li>定义：为各种不同的数据结构提供统一的访问机制</li>
<li>原理：创建一个指针指向首个成员，按照次序使用<code>next()</code>指向下一个成员，直接到结束位置(数据结构只要部署<code>Iterator</code>接口就可完成遍历操作)</li>
<li><strong>作用</strong><ul>
<li>为各种数据结构提供一个统一的简便的访问接口</li>
<li>使得数据结构成员能够按某种次序排列</li>
<li><code>ES6</code>创造了新的遍历命令<code>for-of</code>，<code>Iterator</code>接口主要供<code>for-of</code>消费</li>
</ul>
</li>
<li>形式：<code>for-of</code>(自动去寻找<code>Iterator</code>接口)</li>
<li>数据结构<ul>
<li>集合：<code>Array</code>、<code>Object</code>、<code>Set</code>、<code>Map</code></li>
<li>原生具备接口的数据结构：<code>String</code>、<code>Array</code>、<code>Set</code>、<code>Map</code>、<code>TypedArray</code>、<code>Arguments、NodeList</code></li>
</ul>
</li>
<li>部署：默认部署在<code>Symbol.iterator</code>(具备此属性被认为可遍历的<code>iterable</code>)</li>
<li>遍历器对象<ul>
<li><code>next()</code>：下一步操作，返回<code>{ done, value }</code>(必须部署)</li>
<li><code>return()</code>：<code>for-of</code>提前退出调用，返回<code>{ done: true }</code></li>
<li><code>throw()</code>：不使用，配合<code>Generator</code>函数使用</li>
</ul>
</li>
</ul>
<p><strong>ForOf循环</strong></p>
<ul>
<li>定义：调用<code>Iterator</code>接口产生遍历器对象(<code>for-of</code>内部调用数据结构的<code>Symbol.iterator()</code>)</li>
<li>遍历字符串：<code>for-in</code>获取索引，<code>for-of</code>获取值(可识别32位UTF-16字符)</li>
<li>遍历数组：<code>for-in</code>获取索引，<code>for-of</code>获取值</li>
<li>遍历对象：<code>for-in</code>获取键，<code>for-of</code>需自行部署</li>
<li>遍历<code>Set</code>：<code>for-of</code>获取值 =&gt; <code>for (const v of set)</code></li>
<li>遍历<code>Map</code>：<code>for-of</code>获取键值对 =&gt;  <code>for (const [k, v] of map)</code></li>
<li>遍历类数组：包含<code>length</code>的对象、<code>Arguments</code>对象、<code>NodeList</code>对象(无<code>Iterator</code>接口的类数组可用<code>Array.from()</code>转换)</li>
<li>计算生成数据结构：<code>Array</code>、<code>Set</code>、<code>Map</code><ul>
<li><code>keys()</code>：返回遍历器对象，遍历所有的键</li>
<li><code>values()</code>：返回遍历器对象，遍历所有的值</li>
<li><code>entries()</code>：返回遍历器对象，遍历所有的键值对</li>
</ul>
</li>
<li><strong>与for-in区别</strong><ul>
<li>有着同<code>for-in</code>一样的简洁语法，但没有<code>for-in</code>那些缺点、</li>
<li>不同于<code>forEach()</code>，它可与<code>break</code>、<code>continue</code>和<code>return</code>配合使用</li>
<li>提供遍历所有数据结构的统一操作接口</li>
</ul>
</li>
</ul>
<p><strong>应用场景</strong></p>
<ul>
<li>改写具有<code>Iterator</code>接口的数据结构的<code>Symbol.iterator</code></li>
<li>解构赋值：对<code>Set</code>进行结构</li>
<li>扩展运算符：将部署Iterator接口的数据结构转为数组</li>
<li><code>yield*</code>：<code>yield*</code>后跟一个可遍历的数据结构，会调用其遍历器接口</li>
<li>接受数组作为参数的函数：<code>for-of</code>、<code>Array.from()</code>、<code>new Set()</code>、<code>new WeakSet()</code>、<code>new Map()</code>、<code>new WeakMap()</code>、<code>Promise.all()</code>、<code>Promise.race()</code></li>
</ul>
<h3 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h3><ul>
<li>定义：包含异步操作结果的对象</li>
<li>状态<ul>
<li>进行中：<code>pending</code></li>
<li>已成功：<code>resolved</code></li>
<li>已失败：<code>rejected</code></li>
</ul>
</li>
<li>特点<ul>
<li>对象的状态不受外界影响</li>
<li>一旦状态改变就不会再变，任何时候都可得到这个结果</li>
</ul>
</li>
<li>声明：<code>new Promise((resolve, reject) =&gt; {})</code></li>
<li>出参<ul>
<li><code>resolve</code>：将状态从未完成变为成功，在异步操作成功时调用，并将异步操作的结果作为参数传递出去</li>
<li><code>reject</code>：将状态从未完成变为失败，在异步操作失败时调用，并将异步操作的错误作为参数传递出去</li>
</ul>
</li>
<li>方法<ul>
<li><code>then()</code>：分别指定<code>resolved</code>状态和<code>rejected</code>状态的回调函数<ul>
<li>第一参数：状态变为<code>resolved</code>时调用</li>
<li>第二参数：状态变为<code>rejected</code>时调用(可选)</li>
</ul>
</li>
<li><code>catch()</code>：指定发生错误时的回调函数</li>
<li><code>Promise.all()</code>：将多个实例包装成一个新实例，返回全部实例状态变更后的结果数组(齐变更再返回)<ul>
<li>入参：具有<code>Iterator</code>接口的数据结构</li>
<li>成功：只有全部实例状态变成<code>resolved</code>，最终状态才会变成<code>resolved</code></li>
<li>失败：其中一个实例状态变成<code>rejected</code>，最终状态就会变成<code>rejected</code></li>
</ul>
</li>
<li><code>Promise.race()</code>：将多个实例包装成一个新实例，返回全部实例状态优先变更后的结果(先变更先返回)</li>
<li><code>Promise.resolve()</code>：将对象转为Promise对象(等价于<code>new Promise(resolve =&gt; resolve())</code>)<ul>
<li><code>Promise</code>实例：原封不动地返回入参</li>
<li><code>Thenable</code>对象：将此对象转为<code>Promise</code>对象并返回(<code>Thenable</code>为包含<code>then()</code>的对象，执行<code>then()</code>相当于执行此对象的<code>then()</code>)</li>
<li>不具有<code>then()</code>的对象：将此对象转为<code>Promise</code>对象并返回，状态为<code>resolved</code></li>
<li>不带参数：返回<code>Promise</code>对象，状态为<code>resolved</code></li>
</ul>
</li>
<li><code>Promise.reject()</code>：将对象转为状态为<code>rejected</code>的<code>Promise</code>对象(等价于<code>new Promise((resolve, reject) =&gt; reject())</code>)</li>
</ul>
</li>
</ul>
<p><strong>应用场景</strong></p>
<ul>
<li>加载图片</li>
<li><code>AJAX</code>转<code>Promise</code>对象</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li>只有异步操作的结果可决定当前状态是哪一种，其他操作都无法改变这个状态</li>
<li>状态改变只有两种可能：从<code>pending</code>变为<code>resolved</code>、从<code>pending</code>变为<code>rejected</code></li>
<li>一旦新建<code>Promise</code>对象就会立即执行，无法中途取消</li>
<li>不设置回调函数，内部抛错不会反应到外部</li>
<li>当处于<code>pending</code>时，无法得知目前进展到哪一个阶段</li>
<li>实例状态变为<code>resolved</code>或<code>rejected</code>时，会触发<code>then()</code>绑定的回调函数</li>
<li><code>resolve()</code>和<code>reject()</code>的执行总是晚于本轮循环的同步任务</li>
<li><code>then()</code>返回新实例，其后可再调用另一个<code>then()</code></li>
<li><code>then()</code>运行中抛出错误会被<code>catch()</code>捕获</li>
<li><code>reject()</code>的作用等同于抛出错误</li>
<li>实例状态已变成<code>resolved</code>时，再抛出错误是无效的，不会被捕获，等于没有抛出</li>
<li>实例状态的错误具有冒泡性质，会一直向后传递直到被捕获为止，错误总是会被下一个<code>catch()</code>捕获</li>
<li>不要在<code>then()</code>里定义<code>rejected</code>状态的回调函数(不使用其第二参数)</li>
<li>建议使用<code>catch()</code>捕获错误，不要使用<code>then()</code>第二个参数捕获</li>
<li>没有使用<code>catch()</code>捕获错误，实例抛错不会传递到外层代码，即不会有任何反应</li>
<li>作为参数的实例定义了<code>catch()</code>，一旦被<code>rejected</code>并不会触发<code>Promise.all()</code>的<code>catch()</code></li>
<li><code>Promise.reject()</code>的参数会原封不动地作为<code>rejected</code>的理由，变成后续方法的参数</li>
</ul>
<h3 id="Generator"><a href="#Generator" class="headerlink" title="Generator"></a>Generator</h3><ul>
<li>定义：封装多个内部状态的异步编程解决方案</li>
<li>形式：调用<code>Generator</code>函数(该函数不执行)返回指向内部状态的指针对象(不是运行结果)</li>
<li>声明：<code>function* Func() {}</code></li>
<li>方法<ul>
<li><code>next()</code>：使指针移向下一个状态，返回<code>{ done, value }</code>(入参会被当作上一个<code>yield</code>命令表达式的返回值)</li>
<li><code>return()</code>：返回指定值且终结遍历<code>Generator</code>函数，返回<code>{ done: true, value: 入参 }</code></li>
<li><code>throw()</code>：在<code>Generator</code>函数体外抛出错误，在<code>Generator</code>函数体内捕获错误，返回自定义的<code>new Errow()</code></li>
</ul>
</li>
<li><code>yield</code>命令：声明内部状态的值(<code>return</code>声明结束返回的值)<ul>
<li>遇到<code>yield</code>命令就暂停执行后面的操作，并将其后表达式的值作为返回对象的<code>value</code></li>
<li>下次调用<code>next()</code>时，再继续往下执行直到遇到下一个<code>yield</code>命令</li>
<li>没有再遇到<code>yield</code>命令就一直运行到<code>Generator</code>函数结束，直到遇到<code>return</code>语句为止并将其后表达式的值作为返回对象的<code>value</code></li>
<li><code>Generator</code>函数没有<code>return</code>语句则返回对象的<code>value</code>为<code>undefined</code></li>
</ul>
</li>
<li><code>yield*</code>命令：在一个<code>Generator</code>函数里执行另一个<code>Generator</code>函数(后随具有<code>Iterator</code>接口的数据结构)</li>
<li>遍历：通过<code>for-of</code>自动调用<code>next()</code></li>
<li>作为对象属性<ul>
<li>全写：<code>const obj = { method: function*() {} }</code></li>
<li>简写：<code>const obj = { * method() {} }</code></li>
</ul>
</li>
<li>上下文：执行产生的上下文环境一旦遇到<code>yield</code>命令就会暂时退出堆栈(但并不消失)，所有变量和对象会冻结在当前状态，等到对它执行<code>next()</code>时，这个上下文环境又会重新加入调用栈，冻结的变量和对象恢复执行</li>
</ul>
<p><strong>方法异同</strong></p>
<ul>
<li><strong>相同点</strong>：<ul>
<li><code>next()</code>、<code>throw()</code>、<code>return()</code>本质上是同一件事，作用都是让函数恢复执行且使用不同的语句替换yield命令</li>
</ul>
</li>
<li><strong>不同点</strong><ul>
<li><code>next()</code>：将<code>yield</code>命令替换成一个值</li>
<li><code>return()</code>：将<code>yield</code>命令替换成一个<code>return</code>语句</li>
<li><code>throw()</code>：将<code>yield</code>命令替换成一个<code>throw</code>语句</li>
</ul>
</li>
</ul>
<p><strong>应用场景</strong></p>
<ul>
<li>异步操作同步化表达</li>
<li>控制流管理</li>
<li>为对象部署<code>Iterator</code>接口：把<code>Generator</code>函数赋值给对象的<code>Symbol.iterator</code>，从而使该对象具有<code>Iterator</code>接口</li>
<li>作为具有<code>Iterator</code>接口的数据结构</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li>每次调用<code>next()</code>，指针就从函数头部或上次停下的位置开始执行，直到遇到下一个<code>yield</code>命令或<code>return</code>语句为止</li>
<li>函数内部可不用<code>yield</code>命令，但会变成单纯的暂缓执行函数(还是需要<code>next()</code>触发)</li>
<li><code>yield</code>命令是暂停执行的标记，<code>next()</code>是恢复执行的操作</li>
<li><code>yield</code>命令用在另一个表达式中必须放在圆括号里</li>
<li><code>yield</code>命令用作函数参数或放在赋值表达式的右边，可不加圆括号</li>
<li><code>yield</code>命令本身没有返回值，可认为是返回<code>undefined</code></li>
<li><code>yield</code>命令表达式为惰性求值，等<code>next()</code>执行到此才求值</li>
<li>函数调用后生成遍历器对象，此对象的<code>Symbol.iterator</code>是此对象本身</li>
<li>在函数运行的不同阶段，通过<code>next()</code>从外部向内部注入不同的值，从而调整函数行为</li>
<li>首个<code>next()</code>用来启动遍历器对象，后续才可传递参数</li>
<li>想首次调用<code>next()</code>时就能输入值，可在函数外面再包一层</li>
<li>一旦<code>next()</code>返回对象的<code>done</code>为<code>true</code>，<code>for-of</code>遍历会中止且不包含该返回对象</li>
<li>函数内部部署<code>try-finally</code>且正在执行<code>try</code>，那么<code>return()</code>会导致立刻进入<code>finally</code>，执行完<code>finally</code>以后整个函数才会结束</li>
<li>函数内部没有部署<code>try-catch</code>，<code>throw()</code>抛错将被外部<code>try-catch</code>捕获</li>
<li><code>throw()</code>抛错要被内部捕获，前提是必须至少执行过一次<code>next()</code></li>
<li><code>throw()</code>被捕获以后，会附带执行下一条<code>yield</code>命令</li>
<li>函数还未开始执行，这时<code>throw()</code>抛错只可能抛出在函数外部</li>
</ul>
<blockquote>
<p>首次next()可传值</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Wrapper</span>(<span class="params">func</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params">...args</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">const</span> generator = func(...args);</span><br><span class="line">        generator.next();</span><br><span class="line">        <span class="keyword">return</span> generator;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> print = Wrapper(<span class="function"><span class="keyword">function</span>*(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">`First Input: <span class="subst">$&#123;<span class="keyword">yield</span>&#125;</span>`</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"done"</span>;</span><br><span class="line">&#125;);</span><br><span class="line">print().next(<span class="string">"hello"</span>);</span><br></pre></td></tr></table></figure>
<h2 id="ES2016"><a href="#ES2016" class="headerlink" title="ES2016"></a>ES2016</h2><p><img src="https://poetries1.gitee.io/img-repo/2019/11/126.png" alt></p>
<h3 id="数值扩展-1"><a href="#数值扩展-1" class="headerlink" title="数值扩展"></a>数值扩展</h3><ul>
<li>指数运算符(<code>**</code>)：数值求幂(相当于<code>Math.pow()</code>)</li>
</ul>
<h3 id="数组扩展-1"><a href="#数组扩展-1" class="headerlink" title="数组扩展"></a>数组扩展</h3><ul>
<li><code>includes()</code>：是否存在指定成员</li>
</ul>
<h2 id="ES2017"><a href="#ES2017" class="headerlink" title="ES2017"></a>ES2017</h2><p><img src="https://poetries1.gitee.io/img-repo/2019/11/127.png" alt></p>
<p><strong>声明</strong></p>
<ul>
<li>共享内存和原子操作：由全局对象<code>SharedArrayBuffer</code>和<code>Atomics</code>实现，将数据存储在一块共享内存空间中，这些数据可在<code>JS</code>主线程和<code>web-worker</code>线程之间共享</li>
</ul>
<h3 id="字符串扩展-1"><a href="#字符串扩展-1" class="headerlink" title="字符串扩展"></a>字符串扩展</h3><ul>
<li><code>padStart()</code>：把指定字符串填充到字符串头部，返回新字符串</li>
<li><code>padEnd()</code>：把指定字符串填充到字符串尾部，返回新字符串</li>
</ul>
<p><strong>对象扩展</strong></p>
<ul>
<li><code>Object.getOwnPropertyDescriptors()</code>：返回对象所有自身属性(非继承属性)的描述对象</li>
<li><code>Object.values()</code>：返回以值组成的数组</li>
<li><code>Object.entries()</code>：返回以键和值组成的数组</li>
</ul>
<h3 id="函数扩展-1"><a href="#函数扩展-1" class="headerlink" title="函数扩展"></a>函数扩展</h3><ul>
<li>函数参数尾逗号：允许函数最后一个参数有尾逗号</li>
</ul>
<p><strong>Async</strong></p>
<ul>
<li>定义：使异步函数以同步函数的形式书写(<code>Generator</code>函数语法糖)</li>
<li>原理：将<code>Generator</code>函数和自动执行器<code>spawn</code>包装在一个函数里</li>
<li>形式：将<code>Generator</code>函数的<code>*</code>替换成<code>async</code>，将<code>yield</code>替换成<code>await</code></li>
<li><strong>声明</strong><ul>
<li>具名函数：<code>async function Func() {}</code></li>
<li>函数表达式：<code>const func = async function() {}</code></li>
<li>箭头函数：<code>const func = async() =&gt; {}</code></li>
<li>对象方法：<code>const obj = { async func() {} }</code></li>
<li>类方法：<code>class Cla { async Func() {} }</code></li>
</ul>
</li>
<li><strong>await命令</strong>：等待当前<code>Promise</code>对象状态变更完毕<ul>
<li>正常情况：后面是<code>Promise</code>对象则返回其结果，否则返回对应的值</li>
<li>后随<code>Thenable</code>对象：将其等同于<code>Promise</code>对象返回其结果</li>
</ul>
</li>
<li><strong>错误处理</strong>：将<code>await</code>命令<code>Promise</code>对象放到<code>try-catch</code>中(可放多个)</li>
</ul>
<p><strong>Async对Generator改进</strong></p>
<ul>
<li>内置执行器</li>
<li>更好的语义</li>
<li>更广的适用性</li>
<li>返回值是<code>Promise</code>对象</li>
</ul>
<p><strong>应用场景</strong></p>
<ul>
<li>按顺序完成异步操作</li>
</ul>
<p><strong>重点难点</strong></p>
<ul>
<li><code>Async</code>函数返回<code>Promise</code>对象，可使用<code>then()</code>添加回调函数</li>
<li>内部<code>return</code>返回值会成为后续<code>then()</code>的出参</li>
<li>内部抛出错误会导致返回的<code>Promise</code>对象变为<code>rejected</code>状态，被<code>catch()</code>接收到</li>
<li>返回的<code>Promise</code>对象必须等到内部所有<code>await</code>命令<code>Promise</code>对象执行完才会发生状态改变，除非遇到<code>return</code>语句或抛出错误</li>
<li>任何一个<code>await</code>命令<code>Promise</code>对象变为<code>rejected</code>状态，整个<code>Async</code>函数都会中断执行</li>
<li>希望即使前一个异步操作失败也不要中断后面的异步操作<ul>
<li>将<code>await</code>命令<code>Promise</code>对象放到<code>try-catch</code>中</li>
<li><code>await</code>命令<code>Promise</code>对象跟一个<code>catch()</code></li>
</ul>
</li>
<li><code>await</code>命令<code>Promise</code>对象可能变为<code>rejected</code>状态，最好把其放到<code>try-catch</code>中</li>
<li>多个<code>await</code>命令<code>Promise</code>对象若不存在继发关系，最好让它们同时触发</li>
<li><code>await</code>命令只能用在<code>Async</code>函数之中，否则会报错</li>
<li>数组使用<code>forEach()</code>执行<code>async/await</code>会失效，可使用<code>for-of</code>和P<code>romise.all()</code>代替</li>
<li>可保留运行堆栈，函数上下文随着<code>Async</code>函数的执行而存在，执行完成就消失</li>
</ul>
<h2 id="ES2018"><a href="#ES2018" class="headerlink" title="ES2018"></a>ES2018</h2><p><img src="https://poetries1.gitee.io/img-repo/2019/11/128.png" alt></p>
<h3 id="字符串扩展-2"><a href="#字符串扩展-2" class="headerlink" title="字符串扩展"></a>字符串扩展</h3><ul>
<li>放松对标签模板里字符串转义的限制：遇到不合法的字符串转义返回<code>undefined</code>，并且从<code>raw</code>上可获取原字符串</li>
</ul>
<p><strong>对象扩展</strong></p>
<ul>
<li>扩展运算符(<code>...</code>)：转换对象为用逗号分隔的参数序列(<code>{ ...obj }</code>，相当于<code>rest/spread</code>参数的逆运算)</li>
</ul>
<blockquote>
<p>扩展应用</p>
</blockquote>
<ul>
<li>克隆对象：<code>const obj = { __proto__: Object.getPrototypeOf(obj1), ...obj1 }</code></li>
<li>合并对象：<code>const obj = { ...obj1, ...obj2 }</code></li>
<li>转换字符串为对象：<code>{ ...&quot;hello&quot; }</code></li>
<li>转换数组为对象：<code>{ ...[1, 2] }</code></li>
<li>与对象解构赋值结合：<code>const { x, ...rest/spread } = { x: 1, y: 2, z: 3 }</code>(不能复制继承自原型对象的属性)</li>
<li>修改现有对象部分属性：<code>const obj = { x: 1, ...{ x: 2 } }</code></li>
</ul>
<h3 id="正则扩展-1"><a href="#正则扩展-1" class="headerlink" title="正则扩展"></a>正则扩展</h3><ul>
<li><code>s</code>修饰符：<code>dotAll</code>模式修饰符，使<code>.</code>匹配任意单个字符(<code>dotAll</code>模式)</li>
<li><code>dotAll</code>：是否设置<code>s</code>修饰符</li>
<li>后行断言：<code>x</code>只有在<code>y</code>后才匹配</li>
<li>后行否定断言：<code>x</code>只有不在<code>y</code>后才匹配</li>
<li><strong><code>Unicode</code>属性转义</strong>：匹配符合<code>Unicode</code>某种属性的所有字符<ul>
<li>正向匹配：<code>\p{PropRule}</code></li>
<li>反向匹配：<code>\P{PropRule}</code></li>
<li>限制：<code>\p{...}</code>和<code>\P{...}</code>只对<code>Unicode</code>字符有效，使用时需加上u修饰符</li>
</ul>
</li>
<li><strong>具名组匹配</strong>：为每组匹配指定名字(<code>?&lt;GroupName&gt;</code>)<ul>
<li>形式：<code>str.exec().groups.GroupName</code></li>
<li>解构赋值替换<ul>
<li>声明：<code>const time = &quot;2017-09-11&quot;、const regexp = /(?&lt;year&gt;\d{4})-(?&lt;month&gt;\d{2})-(?&lt;day&gt;\d{2})/u</code></li>
<li>匹配：<code>time.replace(regexp, &quot;$&lt;day&gt;/$&lt;month&gt;/$&lt;year&gt;&quot;)</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="Promise-1"><a href="#Promise-1" class="headerlink" title="Promise"></a>Promise</h3><ul>
<li><code>finally()</code>：指定不管最后状态如何都会执行的回调函数</li>
</ul>
<h3 id="Async"><a href="#Async" class="headerlink" title="Async"></a>Async</h3><ul>
<li>异步迭代器(<code>for-await-of</code>)：，循环等待每个<code>Promise</code>对象变为<code>resolved</code>状态才进入下一步</li>
</ul>
<h2 id="ES2019"><a href="#ES2019" class="headerlink" title="ES2019"></a>ES2019</h2><p><img src="https://poetries1.gitee.io/img-repo/2019/11/129.png" alt></p>
<h3 id="字符串扩展-3"><a href="#字符串扩展-3" class="headerlink" title="字符串扩展"></a>字符串扩展</h3><ul>
<li>直接输入<code>U+2028</code>和<code>U+2029</code>：字符串可直接输入行分隔符和段分隔符</li>
<li><code>JSON.stringify()</code>改造：可返回不符合<code>UTF-8</code>标准的字符串</li>
<li><code>trimStart()</code>：消除字符串头部空格，返回新字符串</li>
<li><code>trimEnd()</code>：消除字符串尾部空格，返回新字符串</li>
</ul>
<h3 id="对象扩展-1"><a href="#对象扩展-1" class="headerlink" title="对象扩展"></a>对象扩展</h3><ul>
<li><code>Object.fromEntries()</code>：返回以键和值组成的对象(<code>Object.entries()</code>的逆操作)</li>
</ul>
<h3 id="数组扩展-2"><a href="#数组扩展-2" class="headerlink" title="数组扩展"></a>数组扩展</h3><ul>
<li><code>flat()</code>：扁平化数组，返回新数组</li>
<li><code>flatMap()</code>：映射且扁平化数组，返回新数组(只能展开一层数组)</li>
</ul>
<h3 id="函数扩展-2"><a href="#函数扩展-2" class="headerlink" title="函数扩展"></a>函数扩展</h3><ul>
<li><code>toString()</code>改造：返回函数原始代码(与编码一致)</li>
<li><code>catch()</code>参数可省略：<code>catch()</code>中的参数可省略</li>
</ul>
<h3 id="Symbol-1"><a href="#Symbol-1" class="headerlink" title="Symbol"></a>Symbol</h3><ul>
<li><code>description</code>：返回<code>Symbol</code>值的描述</li>
</ul>
<h2 id="ES提案"><a href="#ES提案" class="headerlink" title="ES提案"></a>ES提案</h2><p><img src="https://poetries1.gitee.io/img-repo/2019/11/130.png" alt></p>
<h3 id="声明-1"><a href="#声明-1" class="headerlink" title="声明"></a>声明</h3><ul>
<li><code>globalThis</code>对象：作为顶层对象，指向全局环境下的<code>this</code></li>
<li><code>do</code>表达式：封装块级作用域的操作，返回内部最后执行表达式的值(<code>do{}</code>)</li>
<li><code>throw</code>表达式：直接使用<code>throw new Error()</code>，无需<code>()</code>或<code>{}</code>包括</li>
<li><code>!#</code>命令：指定脚本执行器(写在文件首行)</li>
</ul>
<h3 id="数值扩展-2"><a href="#数值扩展-2" class="headerlink" title="数值扩展"></a>数值扩展</h3><ul>
<li>数值分隔符(<code>_</code>)：使用<code>_</code>作为千分位分隔符(增加数值的可读性)</li>
<li><code>BigInt()</code>：创建任何位数的整数(新增的数据类型，使用<code>n</code>结尾)</li>
</ul>
<h3 id="对象扩展-2"><a href="#对象扩展-2" class="headerlink" title="对象扩展"></a>对象扩展</h3><ul>
<li>链判断操作符(<code>?.</code>)：是否存在对象属性(不存在返回<code>undefined</code>且不再往下执行)</li>
<li>空判断操作符(<code>??</code>)：是否值为<code>undefined</code>或<code>null</code>，是则使用默认值</li>
</ul>
<h3 id="函数扩展-3"><a href="#函数扩展-3" class="headerlink" title="函数扩展"></a>函数扩展</h3><ul>
<li>函数部分执行：复用函数功能(<code>?</code>表示单个参数占位符，<code>...</code>表示多个参数占位符)</li>
<li>管道操作符(<code>|&gt;</code>)：把左边表达式的值传入右边的函数进行求值(<code>f(x) =&gt; x |&gt; f</code>)</li>
<li>绑定运算符(<code>::</code>)：函数绑定(左边是对象右边是函数，取代<code>bind</code>、<code>apply</code>、<code>call</code>调用)<ul>
<li><code>bind：bar.bind(foo)</code> =&gt; <code>foo::bar</code></li>
<li><code>apply</code>：bar.apply(foo, arguments)<code>=&gt;</code>foo::bar(…arguments)`</li>
</ul>
</li>
</ul>
<h3 id="Proxy-1"><a href="#Proxy-1" class="headerlink" title="Proxy"></a>Proxy</h3><ul>
<li><code>Promise.try()</code>：不想区分是否同步异步函数，包装函数为实例，使用<code>then()</code>指定下一步流程，使用<code>catch()</code>捕获错误</li>
</ul>
<h3 id="Realm"><a href="#Realm" class="headerlink" title="Realm"></a>Realm</h3><ul>
<li>定义：提供沙箱功能，允许隔离代码，防止被隔离的代码拿到全局对象</li>
<li>声明：<code>new Realm().global</code></li>
</ul>
<h3 id="Class-1"><a href="#Class-1" class="headerlink" title="Class"></a>Class</h3><ul>
<li>静态属性：使用<code>static</code>定义属性，该属性不会被实例继承，只能通过类来调用</li>
<li>私有属性：使用<code>#</code>定义属性，该属性只能在类内部访问</li>
<li>私有方法：使用<code>#</code>定义方法，该方法只能在类内部访问</li>
<li>装饰器：使用<code>@</code>注释或修改类和类方法</li>
</ul>
<h3 id="Module-1"><a href="#Module-1" class="headerlink" title="Module"></a>Module</h3><ul>
<li><strong>import()：动态导入(返回Promise)</strong><ul>
<li>背景：<code>import</code>命令被JS引擎静态分析，先于模块内的其他语句执行，无法取代<code>require()</code>的动态加载功能，提案建议引入<code>import()</code>来代替<code>require()</code></li>
<li>位置：可在任何地方使用</li>
<li>区别：<code>require()</code>是同步加载，<code>import()</code>是异步加载</li>
<li>场景：按需加载、条件加载、模块路径动态化</li>
</ul>
</li>
<li><strong>import.meta：返回脚本元信息</strong></li>
</ul>
<h3 id="Async-1"><a href="#Async-1" class="headerlink" title="Async"></a>Async</h3><ul>
<li>顶层<code>Await</code>：允许在模块的顶层独立使用<code>await</code>命令(借用<code>await</code>解决模块异步加载的问题)</li>
</ul>

      </div>
    
  </div>

</article>

<button class="assist-btn2 circle" id="assist_btn2" title="点亮屏幕" style="left: 27px; top: 152px;">
  <i class="iconfont" style="display:inline-block;color:red;width:20px;height:20px;">&#xe61d;</i>
</button>
<button class="assist-btn1 circle" id="assist_btn1" title="关闭屏幕亮度" style="left: 27px; top: 152px;">
  <i class="iconfont toc-title" style="display:inline-block;color:red;width:20px;height:20px;">&#xe61d;</i>
</button>


<script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>	

<script src="https://my.openwrite.cn/js/readmore.js" type="text/javascript"></script>
<script>
  const btw = new BTWPlugin();
  btw.init({
    id: "container",
    blogId: "22699-1592137983091-414",
    name: "前端进阶之旅",
    qrcode: "https://poetries1.gitee.io/img-repo/2020/06/qrcode.jpg",
    keyword: "3a3b3c",
  });
</script>

<script type="text/javascript">

// white theme
var body = {color: "#555", background: "#000"};
var a_tag = {color: "#222"};
var header = { background: "#222"};
var logo_line_i = {background: "#222"};
// var post_code = {background: "#eee", color: "#222"};

function switch_theme() {
 $("body").css(body);
 $("a:not('.links-of-author-item a, .site-state-item a, .site-state-posts a, .feed-link a, .motion-element a, .post-tags a, .show-commit-cls a, #donate_board a')").css(a_tag);
 $(".header, .footer").css(header);
 $(".logo-line-before i, .logo-line-after i").css(logo_line_i);
 //$(".post code").css(post_code);
 $("#idhyt-surprise-ball #idhyt-surprise-ball-animation .drag").css(a_tag);
 $(".post-title-link, .posts-expand .post-meta, .post-comments-count, .disqus-comment-count, .post-category a, .post-nav-next a, .post-nav-item a").css(a_tag);
 
 // $("code").css({color: '#c5c8c6', background: '#1d1f21'});
 //$("#assist_btn1").hide(1500);
}

$(function () {
$("#assist_btn2").css("display","none");
 $("#assist_btn1").click(function() {
     switch_theme();
$("div#toc.toc-article").css({
 "background":"#eaeaea",
 "opacity":1
});
$(".toc-article ol").show();
$("#toc.toc-article .toc-title").css("color","#a98602");
$("#assist_btn1").css("display","none");
$("#assist_btn2").css("display","block");
 });
$("#assist_btn2").click(function() {
$("#assist_btn2").css("display","none");
$("#assist_btn1").css("display","block");
$("body").css("background","url(http://www.miaov.com/static/ie/images/news/bg.png)")
     $(".header, .footer").css("background","url(http://www.miaov.com/static/ie/images/news/bg.png)")
$(".toc-article ol").toggle(1000);
 });
});


//背景随机

var Y, O, E, L, B, C, T, z, N, S, A, I;
!function() {
var e = function() {
for (O.clearRect(0, 0, L, B), T = [{
x: 0,
y: .7 * B + C
}, {
x: 0,
y: .7 * B - C
}]; T[1].x < L + C;) t(T[0], T[1])
}, t = function(e, t) {
O.beginPath(), O.moveTo(e.x, e.y), O.lineTo(t.x, t.y);
var n = t.x + (2 * I() - .25) * C,
 r = a(t.y);
O.lineTo(n, r), O.closePath(), N -= S / -50, O.fillStyle = "#" + (127 * A(N) + 128 << 16 | 127 * A(N + S / 3) + 128 << 8 | 127 * A(N + S / 3 * 2) + 128).toString(16), O.fill(), T[0] = T[1], T[1] = {
 x: n,
 y: r
}
}, a = function n(e) {
var t = e + (2 * I() - 1.1) * C;
return t > B || t < 0 ? n(e) : t
};
Y = document.getElementById("evanyou"), O = Y.getContext("2d"), E = window.devicePixelRatio || 1, L = window.innerWidth, B = window.innerHeight, C = 90, z = Math, N = 0, S = 2 * z.PI, A = z.cos, I = z.random, Y.width = L * E, Y.height = B * E, O.scale(E, E), O.globalAlpha = .6, document.onclick = e, document.ontouchstart = e, e()
}()

   
$("#toc-eye").click(function(){
$("#toc.toc-article").toggle(1000);
});

</script>


   
  <div class="text-center donation">
    <div class="inner-donation">
      <span class="btn-donation">支持一下</span>
      <div class="donation-body">
        <div class="tip text-center">扫一扫，支持poetries</div>
        <ul>
        
          <li class="item">
            
              <span>微信扫一扫</span>
            
            <img src="/images/weixin.jpg" alt="">
          </li>
        
          <li class="item">
            
              <span>支付宝扫一扫</span>
            
            <img src="/images/zhifubao.jpg" alt="">
          </li>
        
        </ul>
      </div>
    </div>
  </div>


   
  <div class="box-prev-next clearfix">
    <a class="show pull-left" href="/2019/10/07/cordova-for-vue/">
        <i class="icon icon-angle-left"></i>
    </a>
    <a class="show pull-right" href="/2019/12/10/python-base-1/">
        <i class="icon icon-angle-right"></i>
    </a>
  </div>




</div>


  <a id="backTop" class="back-top">
    <i class="icon-angle-up"></i>
  </a>




  <div class="modal" id="modal">
  <span id="cover" class="cover hide"></span>
  <div id="modal-dialog" class="modal-dialog hide-dialog">
    <div class="modal-header">
      <span id="close" class="btn-close">关闭</span>
    </div>
    <hr>
    <div class="modal-body">
      <ul class="list-toolbox">
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/archives/"
              rel="noopener noreferrer"
              target="_self"
              >
              博客
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/categories/"
              rel="noopener noreferrer"
              target="_self"
              >
              分类
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/tags/"
              rel="noopener noreferrer"
              target="_self"
              >
              标签
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/search/"
              rel="noopener noreferrer"
              target="_self"
              >
              搜索
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/link/"
              rel="noopener noreferrer"
              target="_self"
              >
              友链
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/about/"
              rel="noopener noreferrer"
              target="_self"
              >
              关于
            </a>
          </li>
        
      </ul>

    </div>
  </div>
</div>



  
      <div class="fexo-comments comments-post">
    

    

    
    

    

    
    

    

<!-- Gitalk评论插件通用代码 -->
<div id="gitalk-container"></div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css">
<script src="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js"></script>
<script>
const gitalk = new Gitalk({
  clientID: '5567a2c4abb858009d96',
  clientSecret: 'b9039ec056cf5c2346b3cdb63308a28c163f91e5',
  repo: 'poetries.github.io',
  owner: 'poetries',
  // 在这里设置一下截取前50个字符串, 这是因为 github 对 label 的长度有了要求, 如果超过
  // 50个字符串则会报错.
  // id: location.pathname.split('/').pop().substring(0, 49),
  id: location.pathname,
  admin: ['poetries'],
  // facebook-like distraction free mode
  distractionFreeMode: false
})
gitalk.render('gitalk-container')
</script>
<!-- Gitalk代码结束 -->



  </div>

  

  <script type="text/javascript">
  function loadScript(url, callback) {
    var script = document.createElement('script')
    script.type = 'text/javascript';

    if (script.readyState) { //IE
      script.onreadystatechange = function() {
        if (script.readyState == 'loaded' ||
          script.readyState == 'complete') {
          script.onreadystatechange = null;
          callback();
        }
      };
    } else { //Others
      script.onload = function() {
        callback();
      };
    }

    script.src = url;
    document.getElementsByTagName('head')[0].appendChild(script);
  }

  window.onload = function() {
    loadScript('/js/bundle.js?235683', function() {
      // load success
    });
  }
</script>


  <!-- 页面点击小红心 -->
  <script type="text/javascript" src="/js/clicklove.js"></script>
 
  
</body>
</html>
